Group Name: Rentology

Project Name: Visualize Airbnb Rentals in New York City and Los Angeles

Student Name:

Yang Gao (yg2499), Haobo Ma (hm2690), Xin Liu (xl2622)

Introduction

Airbnb is a community-based online platform providing vacation rentals, short rentals along with many other types of rentals all around the world. It is a great choice to find great place to live in and live like a local person. It connects hosts and travelers, facilitating the process of renting without huge expenses but with conveniences. Moreover, it cultivates a sharing-economy by allowing property owners to rent out private properties to benefit the whole community.

Airbnb was founded in 2008 and now is estimated around 25.5 billion USD, which is among the top unicorns in tech world. With such an overwhelmingly popular website, we would like to dig in its datasets and explore what kind of patterns will appear on the visualization. The project is more than likely to provide an insight on what interesting findings will show in the listing prices the review scores, and rental availabilities, etc. In sharing-economy business model, this insight will shed light on future exploration in user preference, which is undoubtedly highly valuable to the firm.

There are several interesting questions to be answered in the project as follows. Firstly, we will check the missing values in datasets we found. This will enable us to figure out the quality of our data. Next, we want to explore the distributions of rental prices according to their cities, their neighborhoods, and their room types. Then we would like to see how minimum nights requirments, availabilities are distributed in different cities/room types. Also, this may shed light on something people did not notice before especially in metropolitans as we selected. Moreover, we would like to explore in depth how many listing residence controlled by the same host. This may enlighten us on if there exists a group of people depending on rentals of Airbnb. If so, we want to know what area the listings will be in. Lastly, we would like to see what factors the review ratings are correlated with in dataset.

We get the data from InsideAirbnb. We would like to select some big cities such as New York City and Los Angeles in United States for this project. Original datasets were compiled by on March 2nd 2017, containing listings which provides summary information and metrics for listings. All listing files saved as csv format. After printing some samples in the original datasets, we think that this website seems to provide quite new datasets and keeps an original touch of data.

The raw listing datasets contain 95 variables and have different data types. The datasets record information about hosts and their rental listings, which is mostly likely to be scraped from Airbnb website directly (Airbnb does not release official datasets, though there are a plenty of unofficial data sources). The raw dataset includes host information such as host id, rental listing description, neighbourhood, property type, room type, minimum nights to stay,review scores, price, etc.

You can easily download the dataset from the website listed in the previous paragraph. For each city, you can click button to see more dataset showing.

Team Members Description

All the team members take care of data cleaning steps, transferring raw data into tidy dataset. We discuss about the variables we need and work together. Once all data cleaning is complete, we move on to create visualization plots.

To generate the visualization plots, Yang will create Scatterplot (based on geographic dimensions), Bar Charts, Histogram,Time Series and Density Plots; Haobo will create text mining and design the WorldCloud as well as the Missing Value heatmap plots; Parallel Coordinate Plot and Mosaic will be created by Xin.

In the report writing, each of us will be responsible for own visualizations in the main analysis. We will integrate our findings and visualization graphics together. We work together on Introduction and limitations in conclusion. Yang and Haobo are also working on Introduction, Analysis of Data Quality and Main Analysis. Xin is for Executive summary and Conclusion. Last but not least, the whole team work together to finalize the project report.

Analysis of Data Quality

library(ggmap)
library(dplyr)
library(ggplot2)
library(plotly)
library(gridExtra)
library(GGally)
library(tm)
library(wordcloud)
library(extracat)
library(ggmosaic)
library(mi)

Load Datasets

#setwd("/Users/gaoyang/Desktop/final")
list0317_ny <- read.csv("/Users/Kevinsnapshow/Columbia University Email/EDV/Data/NYC/March_2017/listings-raw.csv",
                     header = TRUE)
list0317_la <- read.csv("/Users/Kevinsnapshow/Columbia University Email/EDV/Data/LA/03_2017/listings-raw.csv",
                     header = TRUE)
list0317_ny$city_name <- "New York City"
list0317_la$city_name <- "Los Angeles"


#stack raw datasets(stack vertically)
airbnb_total <- rbind(list0317_ny, list0317_la)
airbnb_total$count <-1
airbnb_total$price <- as.numeric(gsub("\\$", "", airbnb_total$price))
airbnb_total_2 <- subset(airbnb_total,select = c(host_since,count,city_name))

Missing Data Analysis

The whole datasets have many different data types, and have more than 50% values in categorical data. We want to check how missing values are spread in this dataset. Here we choose two different methods. First is to load the extracat library and use the visna function to uncover all the combinations that have missing values. Second is the to load the mi package and use the image function to plot the heatmap-like plot of the missing values. We begin with selecting the useful variables which are probably to be used for further anaysis from the original dataset, from both NYC and LA datasets. The details are shown in the following plots:

compareNA <- function(v1,v2) {
    # This function returns TRUE wherever elements are the same, including NA's,
    # and false everywhere else.
    same <- (v1 == v2)  |  (is.na(v1) & is.na(v2))
    same[is.na(same)] <- FALSE
    return(same)
   }
missingdata_ny <- list0317_ny[1:1000,c(1,5:8,10:15,20,22,23,25,26,29,35,37,
                                  40,41,49,50,52,53,61,68,75,77,80,91,95,96)] 
missingdata_la <- list0317_la[1:1000,c(1,5:8,10:15,20,22,23,25,26,29,35,37,
                                  40,41,49,50,52,53,61,68,75,77,80,91,95,96)] 
#New York City missing data
missingdata_ny_1 <- missingdata_ny 
is.na(missingdata_ny_1) <- missingdata_ny_1 =='' #change blank cells into NA
is.na(missingdata_ny_1) <- missingdata_ny_1 =='NA' #NA
visna(missingdata_ny_1, sort = "b",sort.method = "count", fr=50, pmax = 0.05,s =2)

image(missing_data.frame(missingdata_ny_1))
NOTE: In the following pairs of variables, the missingness pattern of the second is a subset of the first.
 Please verify whether they are in fact logically distinct variables.
     [,1]                   [,2]               
[1,] "summary"              "description"      
[2,] "space"                "description"      
[3,] "review_scores_rating" "reviews_per_month"

#Los Angeles missing data
missingdata_la_1 <- missingdata_la
is.na(missingdata_la_1) <- missingdata_la_1 =='' #change blank cells into NA
is.na(missingdata_la_1) <- missingdata_la_1 =='NA' #NA
visna(missingdata_la_1, sort = "b",sort.method = "count", fr=50,pmax = 0.05,s =2)

image(missing_data.frame(missingdata_la_1))
NOTE: In the following pairs of variables, the missingness pattern of the second is a subset of the first.
 Please verify whether they are in fact logically distinct variables.
     [,1]                           [,2]                  
[1,] "summary"                      "description"         
[2,] "space"                        "description"         
[3,] "neighbourhood_group_cleansed" "review_scores_rating"
[4,] "neighbourhood_group_cleansed" "reviews_per_month"   
[5,] "review_scores_rating"         "reviews_per_month"   

From plots above, we can easily see the percentage of missing values in those variables. We will take care of those missing values in further analysis. Due to the local machine capability, the plots are generated by subsetting samples from original datasets.

In addition to the missing values, we also find that there are several columns full of strings/words. We choose to implement text mining technics on those columns along with WordCloud to explore more analytical analysis on customers behavior. We will inlcude more details in Executive Summary session. Overall, the data quality seems good for our research and analysis purposes.

Executive Summary

Time Series Plot of Airbnb Host Register in New York City vs Los Angeles

#time series plot
#plot 1
airbnb_total_2 <- subset(airbnb_total,select = c(host_since,count,city_name))
h1 <- airbnb_total_2 %>% 
  select(host_since,count,city_name) %>%
  group_by(host_since,city_name) %>%
  summarise(Total_Count =sum(count,na.rm=TRUE)) 
h2 <- subset(h1,host_since !="") #remove missing value
h2$date <- format(as.Date(h2$host_since), "%m/%Y")
h2$year <- gsub(".*/","",h2$date)
# change categorical variable
h2$quar[h2$date %in% c('03/2008')] <- "2008 Q1"
h2$quar[h2$date %in% c('04/2008','05/2008','06/2008')] <- "2008 Q2"
h2$quar[h2$date %in% c('07/2008','08/2008','09/2008')] <- "2008 Q3"
h2$quar[h2$date %in% c('10/2008','11/2008','12/2008')] <- "2008 Q4"
h2$quar[h2$date %in% c('01/2009','02/2009','03/2009')] <- "2009 Q1"
h2$quar[h2$date %in% c('04/2009','05/2009','06/2009')] <- "2009 Q2"
h2$quar[h2$date %in% c('07/2009','08/2009','09/2009')] <- "2009 Q3"
h2$quar[h2$date %in% c('10/2009','11/2009','12/2009')] <- "2009 Q4"
h2$quar[h2$date %in% c('01/2010','02/2010','03/2010')] <- "2010 Q1"
h2$quar[h2$date %in% c('04/2010','05/2010','06/2010')] <- "2010 Q2"
h2$quar[h2$date %in% c('07/2010','08/2010','09/2010')] <- "2010 Q3"
h2$quar[h2$date %in% c('10/2010','11/2010','12/2010')] <- "2010 Q4"
h2$quar[h2$date %in% c('01/2011','02/2011','03/2011')] <- "2011 Q1"
h2$quar[h2$date %in% c('04/2011','05/2011','06/2011')] <- "2011 Q2"
h2$quar[h2$date %in% c('07/2011','08/2011','09/2011')] <- "2011 Q3"
h2$quar[h2$date %in% c('10/2011','11/2011','12/2011')] <- "2011 Q4"
h2$quar[h2$date %in% c('01/2012','02/2012','03/2012')] <- "2012 Q1"
h2$quar[h2$date %in% c('04/2012','05/2012','06/2012')] <- "2012 Q2"
h2$quar[h2$date %in% c('07/2012','08/2012','09/2012')] <- "2012 Q3"
h2$quar[h2$date %in% c('10/2012','11/2012','12/2012')] <- "2012 Q4"
h2$quar[h2$date %in% c('01/2013','02/2013','03/2013')] <- "2013 Q1"
h2$quar[h2$date %in% c('04/2013','05/2013','06/2013')] <- "2013 Q2"
h2$quar[h2$date %in% c('07/2013','08/2013','09/2013')] <- "2013 Q3"
h2$quar[h2$date %in% c('10/2013','11/2013','12/2013')] <- "2013 Q4"
h2$quar[h2$date %in% c('01/2014','02/2014','03/2014')] <- "2014 Q1"
h2$quar[h2$date %in% c('04/2014','05/2014','06/2014')] <- "2014 Q2"
h2$quar[h2$date %in% c('07/2014','08/2014','09/2014')] <- "2014 Q3"
h2$quar[h2$date %in% c('10/2014','11/2014','12/2014')] <- "2014 Q4"
h2$quar[h2$date %in% c('01/2015','02/2015','03/2015')] <- "2015 Q1"
h2$quar[h2$date %in% c('04/2015','05/2015','06/2015')] <- "2015 Q2"
h2$quar[h2$date %in% c('07/2015','08/2015','09/2015')] <- "2015 Q3"
h2$quar[h2$date %in% c('10/2015','11/2015','12/2015')] <- "2015 Q4"
h2$quar[h2$date %in% c('01/2016','02/2016','03/2016')] <- "2016 Q1"
h2$quar[h2$date %in% c('04/2016','05/2016','06/2016')] <- "2016 Q2"
h2$quar[h2$date %in% c('07/2016','08/2016','09/2016')] <- "2016 Q3"
h2$quar[h2$date %in% c('10/2016','11/2016','12/2016')] <- "2016 Q4"
h2$quar[h2$date %in% c('01/2017','02/2017','03/2017')] <- "2017 Q1"
h3 <- h2 %>% 
  select(quar,Total_Count,city_name) %>%
  group_by(quar,city_name) %>%
  summarise(Count =sum(Total_Count,na.rm=TRUE)) 
head(h3,10)
ggplot(subset(h3,quar !="2017 Q1"), aes(quar, Count,group =2,color =city_name)) + 
  geom_line(aes(group =city_name), size =2) +
  xlab("Quarter (Year)") +
  theme(axis.text.x = element_text(size=8, angle =40, hjust = 1)) +
  ggtitle("Airbnb Host Register in New York City VS Los Angeles (2008 - 2016)") +
       theme(plot.title = element_text(hjust = 0.5)) +
  geom_text(data=subset(h3,quar !="2017 Q1")[c(33,34,41,42,49,50,57,58,65,66,73,74),], label="Q1",vjust =1, size =4)

As mentioned in the introduction, Airbnb is booming in recent years and attracting more and more new users all around the world. So the first plot presented here is the time series curve for new registers in New York City and Los Angeles from 2008(founded) to 2016. The X axis is measured in quarters and you can easily see the trend is growing rapidly starting from 2010 Q1. Though there are clear downfalls in 2012 Q1 , 2013 Q1 , 2014 Q1 in New York (2013 Q4 in Los Angeles) and 2015 Q1 in New York (2014 Q4 in Los Angeles), especially in 2014, the general trend is yet undoubtedly an increasing one.

The very intriguing finding is decreasing pattern for Q1, as marked in plot. The pattern may be answered by more professional business insiders. Q1 (sometimes Q4 it depends) might be a bad quarter for business in general or so. Now what we care more is that the very steep fall in Los Angeles 2016 Q4. The drop is so large that we nearly suspect that data is somehow wrong in this quarter. However, we found this news: L.A. Is Poised to Enact Strict Airbnb Regulations, the strict regulations may explain why Airbnb is experiencing a fierce winter in Los Angeles. So now, we have already learned a basic idea about Airbnb.

Boxplot of Airbnb Rental Price in New York City vs Los Angeles

#boxplot NYC vs LA
#plot 2
airbnb_total_3 <- subset(airbnb_total, price <= 500)
ggplot(subset(airbnb_total_3), aes(x=room_type, y=price, fill=city_name)) +
  geom_boxplot() +
  xlab("Room Type") +
  ylab("Price in Dollars (USD)") +
  ggtitle("Price By Room Type in New York City Vs Los Angeles") +
  theme(plot.title = element_text(hjust = 0.5))

After checking the new registers for Airbnb, we then look closer at how the prices distribute in New York City and Los Angeles. A multiple box-plot is exploited here. It utilized not only the price variable, but also the room types.

We want to addres that we filter out all the listings that are higher than 500 dollars since they are obvious outliers in histogram, which will be mentioned in main analysis. To achieve a better visualizaiton of prices, we want to kepp the prices under 500. With after-filtering data, we construct this box-plot.

The first impression is that prices in New York City is generally higher than those in Los Angeles. All three NY boxes are higher than LA ones. It shows that prices for each room type, NY is generally higher. Specifically, prices are almost the same for private room. For entire home/apt, NY box is clearly higher than LA, As for shared room, NY box is much higher than LA one. The distinction between room types are new findings.

Next, we are not surprised to see that there are still a large amount of outliers in higher price level. But look at the details here. For shared rooms, the outliers are sparse. For private room, the outliers seems to become more. And both of them have relatively short whiskers. When it comes to entire home/apt, it has long whiskers and a lot of outliers. We can easily assume that entire home/apt are varing a lot in price and it gets the highest listing price in whole dataset. And it is reasonale finding that one entire home/apt can be very expensie in NYC/LA.

Word Cloud Discovery

#word count
#plot 3
#NYC word counts
h2_ny <-subset(list0317_ny, select=c("summary","description","neighborhood_overview","notes","transit","price","access","interaction"))
h2_ny_merge<- do.call(paste0, list0317_ny[c("summary","description","neighborhood_overview","notes","transit","price","access","interaction")])
h2_ny_union=h2_ny_merge[sample(length(h2_ny_merge),6000)]
docs_ny <- Corpus(VectorSource(h2_ny_union))
toSpace <- content_transformer(function (x , pattern ) gsub(pattern, " ", x))
docs_ny <- tm_map(docs_ny, toSpace, "/")
docs_ny <- tm_map(docs_ny, toSpace, "@")
docs_ny <- tm_map(docs_ny, toSpace, "\\|")
docs_ny <- tm_map(docs_ny, content_transformer(tolower))
# Remove numbers
docs_ny <- tm_map(docs_ny, removeNumbers)
# Remove english common stopwords
docs_ny <- tm_map(docs_ny, removeWords, stopwords("english"))
# Remove your own stop word
# specify your stopwords as a character vector
docs_ny <- tm_map(docs_ny, removeWords, c("blabla1", "blabla2")) 
# Remove punctuations
docs_ny <- tm_map(docs_ny, removePunctuation)
# Eliminate extra white spaces
docs_ny <- tm_map(docs_ny, stripWhitespace)
# Text stemming
# docs <- tm_map(docs, stemDocument)
dtm_ny <- TermDocumentMatrix(docs_ny)
m_ny <- as.matrix(dtm_ny)
v_ny <- sort(rowSums(m_ny),decreasing=TRUE)
d_ny <- data.frame(word = names(v_ny),freq=v_ny)
head(d_ny, 10)
#LA word counts
h2_la <-subset(list0317_la, select=c("summary","description","neighborhood_overview","notes","transit","price","access","interaction"))
h2_la_merge<- do.call(paste0, list0317_la[c("summary","description","neighborhood_overview","notes","transit","price","access","interaction")])
h2_la_union=h2_la_merge[sample(length(h2_la_merge),6000)]
docs_la <- Corpus(VectorSource(h2_la_union))
toSpace <- content_transformer(function (x , pattern ) gsub(pattern, " ", x))
docs_la <- tm_map(docs_la, toSpace, "/")
docs_la <- tm_map(docs_la, toSpace, "@")
docs_la <- tm_map(docs_la, toSpace, "\\|")
docs_la <- tm_map(docs_la, content_transformer(tolower))
# Remove numbers
docs_la <- tm_map(docs_la, removeNumbers)
# Remove english common stopwords
docs_la <- tm_map(docs_la, removeWords, stopwords("english"))
# Remove your own stop word
# specify your stopwords as a character vector
docs_la <- tm_map(docs_la, removeWords, c("blabla1", "blabla2")) 
# Remove punctuations
docs_la <- tm_map(docs_la, removePunctuation)
# Eliminate extra white spaces
docs_la <- tm_map(docs_la, stripWhitespace)
# Text stemming
# docs <- tm_map(docs, stemDocument)
dtm_la <- TermDocumentMatrix(docs_la)
m_la <- as.matrix(dtm_la)
v_la <- sort(rowSums(m_la),decreasing=TRUE)
d_la <- data.frame(word = names(v_la),freq=v_la)
head(d_la, 10)
set.seed(1234)
par(mfrow=c(1,2))
w1 <- wordcloud(words = d_ny$word, freq = d_ny$freq, min.freq = 1,
          max.words=200, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2")) #NYC
w2 <- wordcloud(words = d_la$word, freq = d_la$freq, min.freq = 1,
          max.words=200, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2")) #LA

This is an interesting visualizaiton when you want to know what the text content of listings will be about in Airbnb. It reflects what might be attractive to travallers, what respects are considered important when renting a place. However, due to the limited capability of local machine, we have to select 6000 samples from New York City and Los Angeles respectively.

We count the appearance for each word in the following varibales: summary, description, neighborhood_overview, notes, transit, price, access, interaction. These are all text content variables. And the more counts a word gets, the larger it shows in visualizaiton.

The result is very clear. When you put them together, you can tell which is NYC/LA with only one glance. The huge ‘hollywood’, ‘beach’ are identifying itself as Los Angeles. And also you can see ‘Manhattan’ in NYC visualization These two cities are very distinctive in the word count visualization.

What’s more to be noticed? Los Angeles one has ‘house’ and New York one has not. And you can imagine that the number of houses in Los Angeles may be more than that of New York City. ‘Kitchen’ shows in both visualizations and not a small one. It is surprising that people care about kitchen that much. Usually it is assumed that people will avoid cooking when they travel. But it seems not the truth.

Main Analysis

Rental Listing Distribution Analysis

In the first steo to explore Airbnb dataset deeply, we would like to look at how rental listing distributed in both New York City and Los Angeles.

#Airbnb Room Type Distribution in New York City
qmplot(longitude, latitude, data = list0317_ny, maptype = "toner-background",
       darken = 0.7,color = room_type,alpha =I(0.4),size = I(0.1)) +
       guides(colour = guide_legend(override.aes = list(size=2))) +
       ggtitle("Airbnb Room Type Distribution in New York City ") +
       theme(plot.title = element_text(hjust = 0.5)) +
       facet_wrap(~ room_type)

#Airbnb Room Type Distribution in Los Angeles
qmplot(longitude, latitude, data = list0317_la, maptype = "toner-background",
       darken = 0.7, color = room_type,alpha =I(0.4),size = I(0.1)) +
       guides(colour = guide_legend(override.aes = list(size=2))) +
       ggtitle("Airbnb Room Type Distribution in Los Angeles") +
       theme(plot.title = element_text(hjust = 0.5)) +
       facet_wrap(~ room_type)

As we can clearly see in the plot,there are a lot of entire home/apt and private room locate in Manhattan,Downtown Brooklyn,and Queens.Also,it provides a lot of private room in Flushing,Queens and Staten Island.It shows that there have some entire home/apt and private room in Staten Island and Bronx,while there are few numbers of shared room locate in these areas,most of them locate in Manhattan and Downtown Brooklyn.

Let’s see how Los Angeles data looks like.A large amount of entire home/apt and private room locate nearby the beach,such as Santa Monica and Long Beach.Los Angeles people loves sunshine and beach! Also,there are a lot of entire home/apt and private room in DTLA,Pasadena and Glendora area.While most of shared room located in DTLA and Santa Monica.At the left side corner,it’s called Santa Catalina Island.It provide a lot of entire home/apt and private room in this small island.

Price Comparison between New York City and Los Angeles

We consider that most travelers concern price if it is expensive or cheap.So we conducted the histogram for price variable.As it shows in the plot,a large amount of rental listing price ranges from 10 to 350.The distribution of price looks like right skewed.There are a lot of outliers that price over 500 USD.So we built a density plot which compared with two cities New York City and Los Angeles.Based on density plot,the peak value for shared room price ranges from 10 to 50.While the peak value for private room price ranges from 50 to 100.And the peak value for entire room price ranges from 100 to 200.It provides you an option to choose a suitable room type that you would like to stay.All peak value moves right in New York City which compares with Los Angeles.That means the average price in New York is much higher than that in Los Angeles.

# Price compare with NYC and LA.
# Summarize Listing Price 
summary(airbnb_total$price)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
   10.0    70.0   100.0   138.6   169.0   999.0     624 
ggplot(data=airbnb_total, aes(airbnb_total$price)) + 
  geom_histogram(binwidth = 28,
                 col ='black',
                 fill="lightblue") + 
  labs(title="Histogram for Listing Price") +
  theme(plot.title = element_text(hjust = 0.5)) +
  labs(x="Listing Price", y="Frequency")

ggplot(airbnb_total_3, aes(price, colour = room_type)) +
  geom_density(size=1, show.legend = FALSE) + 
  stat_density(aes(x=price, colour=room_type), geom="line", position="identity" )  +
  guides(colour = guide_legend(override.aes = list(size=2)))+
  xlab("Price") +
  ggtitle("Density Distribution of Price By Room Type") +
       theme(plot.title = element_text(hjust = 0.5)) +
  facet_wrap( ~city_name ,ncol= 1)

ggplot(subset(airbnb_total_3,city_name =="New York City"), aes(x=neighbourhood_group_cleansed, y=price, fill=room_type)) +
  geom_boxplot() +
  xlab("District Area") +
  ylab("Price in Dollars (USD)") +
  ggtitle("Price By Room Type in Different Areas in New York City") +
  theme(plot.title = element_text(hjust = 0.5))

So we want to deeply look at the price based on type of room and district areas in both cities. Unfortunately, district area variable(neighbourhood_group_cleansed) is not available in Los Angeles, so we will only explore in New York City data.Accordning to the result of boxplot,price of entire home/apt is much expensive than the other two. Private room is the second expensive one.Shared room provides the cheapest price.As we can see,although we remove outliers that price over 500 USD,it still have a lot of outliers in the boxplot based on different room type and different district area.It shows that rooms in Manhattan is much expensive than other district.The median price of entire room/apt in Manhattan is around 180 USD.And the median price of private room in Manhattan is less 100 USD,around 80 USD. So if we want to save some money,we suggest that you can choose private room in Manhattan and look at other discrict area,such as Brooklyn and Queens.

Parallel Coordinate Plot of Various Price Levels

# PCP Plot 
abn <- airbnb_total[airbnb_total$price <= 500 , ]
quantile(abn$price, probs = c(0, 0.25, 0.5, 0.75, 1), na.rm = TRUE)
  0%  25%  50%  75% 100% 
  10   69  100  160  500 
abn$security_deposit[abn$security_deposit==""] <- '0'
abn$cleaning_fee[abn$cleaning_fee==""] <- '0'
abn$security_deposit <- as.numeric(abn$security_deposit)
abn$cleaning_fee <- as.numeric(abn$cleaning_fee)
abn$security_deposit[is.na(abn$security_deposit)] <- 0
abn$cleaning_fee[is.na(abn$cleaning_fee)] <- 0
abn$extra_fee <- abn$security_deposit + abn$cleaning_fee
pcp <- abn[abn$extra_fee > 0, ]
pcp <-subset(pcp,select=c("price","city_name","room_type","host_response_time","review_scores_rating","extra_fee"))
#nrow(pcp)
pcp$priceLevel <- '0 - 25%'
pcp$priceLevel[pcp$price>=69] <- '25% - 50%'
pcp$priceLevel[pcp$price>=100] <- '50% - 75%'
pcp$priceLevel[pcp$price > 160] <- '75% and above'
pcp_sample <-pcp[sample(1:nrow(pcp), 25000, replace=FALSE),]
ggparcoord(pcp_sample, columns = 2:6 , groupColumn = 'priceLevel', scale = 'uniminmax', title = "Parallel Coordinate Plot for Price Level (sample size = 25000)") +
  geom_line(size=1.25) +
  labs(y="")+
  theme(axis.text.x=element_text(angle=5, hjust=1), 
        axis.ticks.y = element_blank(),
        plot.title = element_text(hjust = 0.5))

Parallel coordinate plot is ideal for showing how one single variable is changing in coordination with a a series of varibales. Here, the single variable is price level and the variables we want to look at are cities, room types, host response time, review score ratings, and extra fee.

Extra fee is not a variable from original dataset. It is a sum of security deposit and cleaning fee if either of it exists. We want to createt this label since we believe that rent price might be correlated with the extra amount of money. In real life, one can easily assume that, the better an accommodation is. the higher price it takes. When you visit a luxury hotel, you are more likely to pay higher security deposit and cleaning fee after staying. That is why we create this variable to check if it is correlated with rent price.

When plotting PCP, the large amount of data cannot be handled by our local machine. So it is better to take a sample to do plotting. The size 25000 is nearly the maximum which local machine is capable of. One thing need to be noticed is that we exclude samples whose extra fee equaling to zero. It is better to check the correlation between extra fee and rent price. And the total size of data with extra fee being larger than zero is more than 40000. It is very reasonable to take a sample from that large size.

Looking at this PCP, the first three variables are discreate ones. We can easily see that 0 - 25% are very active in these three variables. So we know 0 - 25% have large spreat in cities, room types, and host response time. In last two variables, two points need to be noticed. One is that purple line appears more in top, which means high price correlates with high ratings and more extra fee. There seems to be some outliers in high extra fee. These high extra fee are more likely to be 75% and above price level. The other point is that score rating is tend to higher. It might indicate that people like to give a good score to the hosts. More details on these variables will be in following parts.

Availablity Analaysis

Let’s look at Availablity_365 variable.It shows the number of days the residence is available to renters by the host within 365 days span after the listing was posted.This is a factor to see whether these rental listing is under leave unused.First,we explore a summary to see this variable.The median value equals to 143 days,and mean value equals to 168.6 days.That means there are almost half a year the residence is under leave unused.So people would like to share their residence to other people if they need.Based on histogram,there are two peaks in the plot.A large amount of residence listing fall into 1-10 days and 355-365 days.Also,there are a lot available listing ranges from 10-100 days and 270 -365 days.So we tranform numerical variable into categorical variable with 4 levels(1-3 months,4-6 months,7-9 months,and 10-12 months).

# Availablity_365
airbnb_total$availability_365 <- as.numeric(airbnb_total$availability_365)
summary(airbnb_total$availability_365)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    0.0     4.0   143.0   168.6   334.8   365.0 
ggplot(data=airbnb_total, aes(airbnb_total$availability_365)) + 
  geom_histogram(binwidth = 10,
                 col ='black',
                 fill="lightblue") + 
  labs(title="Histogram for Availability") +
  theme(plot.title = element_text(hjust = 0.5)) +
  labs(x="Available Days", y="Frequency")

# create Available_Quarter based on Availablity_365
airbnb_total$available_quarter[airbnb_total$availability_365 <=91 &
                              airbnb_total$availability_365 >=0] <- "1-3 Months"
airbnb_total$available_quarter[airbnb_total$availability_365 <=181 &   
                               airbnb_total$availability_365 >91] <- '4-6 Months'
airbnb_total$available_quarter[airbnb_total$availability_365 <=271 &  
                               airbnb_total$availability_365 >181] <- '7-9 Months'
airbnb_total$available_quarter[airbnb_total$availability_365 <= 365&   
                               airbnb_total$availability_365 >271] <- '10-12 Months'
airbnb_total$available_quarter <- factor(airbnb_total$available_quarter)
airbnb_total$available_quarter <- factor(airbnb_total$available_quarter, 
                                        levels = c("1-3 Months", "4-6 Months", 
                                                   "7-9 Months", "10-12 Months"))
summary(airbnb_total$available_quarter)
  1-3 Months   4-6 Months   7-9 Months 10-12 Months 
       29117         6853         4421        23567 
ggplot(airbnb_total, aes(availability_365, colour = room_type)) +
  geom_density(size =1 , show.legend = FALSE) +
  xlab("Available Days") +
  ggtitle("Density Distribution of Availability ") +
       theme(plot.title = element_text(hjust = 0.5)) + 
  stat_density(aes(x=availability_365, colour=room_type), geom="line", position="identity" )  +
  guides(colour = guide_legend(override.aes = list(size=2)))

The histogram makes an interesting distribution in available days. Both the bars at the beginning and the end have extremely high counts, which means that there are a large percentage of hosts are either available for only a few days in a year or available almost for a whole year. Then we have an assumption that the hosts are not updating their availability on the website so they are recorded as available for 365 days. Then we try to eliminate the value of 365 and plot again. But the trend still keeps. Thus we think the original data may indicate that quite a percentage of hosts are doing Airbnb for a casual days and do not depend on the rent money while another large proportion of people are depending on it.

The density shows how available days distributes in room types. We can see that shared room type does not keep the trend at the beginning bar. It appears that shared rooms are having more availability compared to others. Now we might imagine that shared rooms are more flexible than entire ones so it will have more availability. It is further validated by the fact that entire home/apt is going low at the end of density, which means there is less people are renting entire home/apt for a long period compared to other room types.

#NYC 
g <- ggplot(subset(airbnb_total,neighbourhood_group_cleansed !="NA"), aes(available_quarter, fill=neighbourhood_group_cleansed)) + 
  geom_bar(position = "dodge") +
  xlab("Available Days") +
  ggtitle("Available Stays in Difference Zones(New York) by Room Type") +
  theme(axis.text.x = element_blank(),
        #axis.text.x = element_text(angle =30,hjust = 1),
        plot.title = element_text(hjust = 0.5))+
  facet_wrap( ~room_type)
ggplotly(g)

Entire room/apt has large numbers of available residence in 1-3 months, the 2nd largest number of available residence is in 10-12 months, then 4-6 months and 7-9 months.It didn’t show much available residence for shared room in 4-6 monts and 7-9 months.

Within Entire Room/Apt type,Manhattan area provides the largest available listings through a whole year.The second largest available listings is in Brooklyn,especially if you want to stay within 1-3 months short term or 10-12 months long term.In private room residence,Brooklyn area provides the largest available residence in 1-3 months and 10-12 months.So if you consider that Entire Room/Apt cost you too much,choosing private room in Brooklyn is a good choice.But if you think 1-3 months is too short and 10 -12 months is too long,you can also find a good place in Manhattan and Brooklyn.Manhattan provides over thousand available Entire Room/Apt residence in 4-6 months option.Also,Brooklyn provides less thousand,around 800 listings in 4- 6 months.

Minimun Nights Requirement Analysis

We also would like to check that whether those available residence have minimum stays requirement. We choose minimum nights variable to explore. Based on summary report,all rental listings require minimum 1 night stay.The median value equals to 2,and mean value equals to 3.7 nights.That means the average minimum requires 4 nights to stay.Then we make a new categorical variable to transform numerical one.In new variable,there are 5 levels(1 nights,2-3 nights,4-5 nights,6-7 nights,and 7 more nights).

#minimun nights requirement
summary(airbnb_total$minimum_nights)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
   1.000    1.000    2.000    3.674    3.000 1250.000 
airbnb_total$cat_night[airbnb_total$minimum_nights ==1] <- "1 Night"
airbnb_total$cat_night[airbnb_total$minimum_nights >1 & airbnb_total$minimum_nights <=3] <- "2-3 Nights"
airbnb_total$cat_night[airbnb_total$minimum_nights >3 & airbnb_total$minimum_nights <=5] <- "4-5 Nights"
airbnb_total$cat_night[airbnb_total$minimum_nights >5 & airbnb_total$minimum_nights <=7] <- "6-7 Nights"
airbnb_total$cat_night[airbnb_total$minimum_nights >7 & airbnb_total$minimum_nights <=30] <- "7 Nights More"
airbnb_total$price <- as.numeric(gsub("\\$", "", airbnb_total$price)) #remove $ sign
table(airbnb_total$cat_night,airbnb_total$room_type)
               
                Entire home/apt Private room Shared room
  1 Night                  9703        13368        1690
  2-3 Nights              15715         9779         449
  4-5 Nights               4094         2177          81
  6-7 Nights               1776         1160          89
  7 Nights More            2068         1379          94
table(airbnb_total$cat_night)

      1 Night    2-3 Nights    4-5 Nights    6-7 Nights 7 Nights More 
        24761         25943          6352          3025          3541 
ggplot(subset(airbnb_total,cat_night !="NA"), aes(cat_night, fill =room_type)) + 
  geom_bar() +
  xlab("Minimum Nights(Days)") +
  ggtitle("Minimum Nights by Room Type") +
  theme(plot.title = element_text(hjust = 0.5)) +
  facet_wrap(~ city_name) +
  coord_flip()

g <-ggplot(subset(airbnb_total,price <=500  & cat_night !="NA"), aes(price, colour = cat_night)) +
  geom_density(size = 1, show_guide = FALSE) +
  xlab("Price") +
  ggtitle("Density Distribution of Price By Minimum Nights") +
       theme(plot.title = element_text(hjust = 0.5))+ 
  stat_density(aes(x=price, colour=cat_night), geom="line", position="identity" )  +
  guides(colour = guide_legend(override.aes = list(size=2)))
ggplotly(g)

In New York City,the largest number of minimum stays is 2-3 nights in New York City, while the largest number of minimum stays is 1 nights in Los Angeles.So New York City may have more strict booking policy than that in Los Angeles.We will explore this problem on further discussions.It seems that a large number of listings in private room has 1 nights minimum within both cities,while entire home/apt has larger number of listings in both cities for 2-3 nights minimum.

Based on desity plot,price ranges from 10 to 100 USD,it provides more friendly minimum nights requirement for only 1 night.Price ranges from 100 to 300 USD,most rental listings require 2-3 nights minimum.While price over 300 USD,a lot of listings require 4-5 nights or more minimum stays.

Top Host Listings Analysis

In order to represent, compare and analylize the top hosts in NYC and/v.s. LA, we choose to use The celevland dot plot to show the total host numbers in a descending order. Alexander from LA has the most total_count of 42 hosting and ranks at the first place. On the top 35 listings, over than 85% are from LA. It shows the consistantcy and professionism differences between NYC and LA in general. In short, LA top hosters are more reliable and professional to most renters.

# host_id 
# which host has most rental listing? TOP 60 host ID in each city
h4 <- airbnb_total %>% 
  select(host_id,host_name,count,city_name) %>%
  group_by(host_id,host_name,city_name) %>%
  summarize(Total_Count =sum(count,na.rm=TRUE)) %>%
  arrange(desc(Total_Count)) 
# select top 30 in NYC
h4_1 <- h4 %>%
  filter(city_name =='New York City') %>%
  head(30)
# select top 30 in LA
h4_2 <- h4 %>%
  filter(city_name =='Los Angeles') %>%
  head(30)
h4_3 <- rbind(h4_1,h4_2)
h4_4 <- h4_3 %>%
  arrange(desc(Total_Count))
  
head(h4_4)

Top 60 hosts in New York City and Los Angeles

 ggplot(h4_4, aes(x= reorder(host_name,Total_Count),y=Total_Count,color=city_name)) + 
  geom_point()+
  xlab("Host ID") +
  ggtitle("Top Hosts in New York City Vs Los Angeles") +
       theme(plot.title = element_text(hjust = 0.5)) +
  coord_flip()

Top 50 Hosting in New York City

h4_1_1 <- h4 %>%
  filter(city_name =='New York City') %>%
  head(50)
h4_1_2 <-subset(h4_1_1, select=c("host_id","host_name"))
list0317_ny_2 <- list0317_ny
list0317_ny_2$price <- as.numeric(gsub("\\$", "", list0317_ny_2$price)) #remove $ sign
sub_merge <- subset(list0317_ny_2,select =c("host_id","neighbourhood_group_cleansed","latitude",
               "longitude","property_type","room_type","price","minimum_nights","maximum_nights"))
# LEFT JOIN
h1_total <- merge(x = h4_1_2, y = sub_merge, by = "host_id", all.x = TRUE) # top 50 host ID NYC
# 50 Host Listing in NYC
g1 <- qmplot(longitude, latitude, data = h1_total, maptype = "toner-background",
       darken = 0.6, color = room_type,alpha =I(0.4),size = I(0.6))+
      guides(colour = guide_legend(override.aes = list(size=3))) +
      ggtitle("Top 50 Host in New York") +
      theme(legend.text=element_text(size=8))
g2 <- qmplot(longitude, latitude, data = h1_total, maptype = "toner-background",
       darken = 0.6, color = property_type,alpha =I(0.4),size = I(0.6)) +
      guides(colour = guide_legend(override.aes = list(size=3))) +
      ggtitle("Top 50 Host in New York")+
      theme(legend.text=element_text(size=8))
grid.arrange(g1,g2, nrow=1)

Top 50 Hosting in Los Angeles

#Top 50 Host ID LA
###################
h4_1_1_la <- h4 %>%
  filter(city_name =='Los Angeles') %>%
  head(50)
h4_1_2_la <-subset(h4_1_1_la, select=c("host_id","host_name"))
list0317_la_2 <- list0317_la
list0317_la_2$price <- as.numeric(gsub("\\$", "", list0317_la_2$price)) #remove $ sign
sub_merge_la <- subset(list0317_la_2,select =c("host_id","neighbourhood_group_cleansed","latitude",
               "longitude","property_type","room_type","price","minimum_nights","maximum_nights"))
# LEFT JOIN
h1_total_la <- merge(x = h4_1_2_la, y = sub_merge_la, by = "host_id", all.x = TRUE) # top 50 host ID LA
g3 <- qmplot(longitude, latitude, data = h1_total_la, maptype = "toner-background",
       darken = 0.6, color = room_type,alpha =I(0.4),size = I(0.6))+
      guides(colour = guide_legend(override.aes = list(size=3))) +
      ggtitle("Top 50 Host in Los Angeles") +
      theme(legend.text=element_text(size=8))
g4 <- qmplot(longitude, latitude, data = h1_total_la, maptype = "toner-background",
       darken = 0.6, color = property_type,alpha =I(0.4),size = I(0.6)) +
      guides(colour = guide_legend(override.aes = list(size=3))) +
      ggtitle("Top 50 Host in Los Angeles")+
      theme(legend.text=element_text(size=8))
grid.arrange(g3,g4, nrow=1)

From the top 50 Host Listing plot in NYC, we can see that the most room type is Private room and the most property_type is Apartment; whereas in LA, the most room types are Entire home/apt and Shared room, and House and Loft are the two main property_types that are mostly determined by the areas. In addition, if it’s located more close to downtown and UCLA area, we can also see some Apartment and Condominium point plots showing up.

Facetting MOSAIC for superhost/verified host/neighborhood in NYC

#Facetting MOSAIC for superhost, verified, neighbprhood in NYC
msc <- subset(list0317_ny,select = c(host_identity_verified, neighbourhood_group_cleansed,host_is_superhost ) )
msc <- msc[msc$host_identity_verified!="",]
levels(msc$host_identity_verified) <- c(levels(msc$host_identity_verified), "YES","NO")
levels(msc$host_is_superhost) <- c(levels(msc$host_is_superhost), "Superhost","Not Superhost")
msc$host_identity_verified[msc$host_identity_verified == "t"] <- "YES"
msc$host_identity_verified[msc$host_identity_verified == "f"] <- "NO"
msc$host_is_superhost[msc$host_is_superhost == "t"] <- "Superhost"
msc$host_is_superhost[msc$host_is_superhost == "f"] <- "Not Superhost"
mosaic <- ggplot(data = msc) +
   geom_mosaic( aes( x = product(host_identity_verified, neighbourhood_group_cleansed), fill=factor(host_identity_verified)),  na.rm=TRUE) +     
  theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.ticks = element_blank()) +
  labs(x="Neighborhoods", title='NYC verified hosts, superhosts Neighborhoods ')  +
  facet_grid(host_is_superhost~.) + 
  guides(fill=guide_legend(title = "Identity Verified") ) 

This is a facetting mosaic plot comparing the number of hosts/verified hosts/superhosts in different neighborhoods in new york city.

Firstly, we can look at how hosts is distributed in differnet neighborhoods. It is easily to see that Manhattan and Brooklyn have much larger amount of hosts than other neighborhoods. Staten Island is no doubt occupying the smallest part. Next, we will look at the verified hosts and unverified hosts. Surprisingly, unverified hosts seem to have a larger percentage in Manhattan than in Brooklyn. And it is also notieable that unverified hosts are counting a rather large percentage in the total number of hosts. Usually the travellers will like to live in a more secure space so verification is an important factor when one is looking for accommodations. Such a large percentage of unverified hosts give us two guesses. One is that peole here are so concerned about their privacy that they do not want to be verified even just by Airbnb. The other one is that accommodations in new york city is so pricy that traveller will more than willingly to pay a lower price and leave the verification issue alone.

Lastly, the superhosts. When we facet with superhost, it is not according to the percentage of superhost or not. In fact, the number of superhosts is much smaller than the one of not superhosts. But it is very reasonable since only the top hosts can be deemed as superhosts by Airbnb. For example, when you want to buy something on eBay, you will want to look at top rated sellers. If everyone is top rated seller, then the title is meaningless. One can easily notice that verified superhosts are covering a larger area compared to not superhosts facet. And one very important finding is that, Brooklyn seems to have more superhosts than Manhattan, which is genuinly unexpected. Maybe it is a proof of success in gentrification.

Review Score Rating Analysis

Another important metric for our data analysis is the Review Score Rating. We want to explore and see if there’s any major factor that will make difference on the Review Score Rarting of the host listings. We selected Number of Reviews, host_is_superhost and host_response_time as another three variables to visulaize the relationship associated with Review Score Rating.

RReview Score Rating vs Superhost

# reviews
# host_is_superhost 
summary(airbnb_total$host_is_superhost)
          f     t 
   24 55151  8783 
re_super <- subset(airbnb_total,host_is_superhost !="") #remove missing value
ggplot(re_super, aes(number_of_reviews, review_scores_rating)) +
  geom_point(aes(colour = factor(host_is_superhost)),alpha =0.6) +
  xlab("Number of Reviews") +
  ylab("Review Scores Rating") +
  ggtitle(" Distribution of Review Scores Rating by Super Host ") +
       theme(plot.title = element_text(hjust = 0.7)) +
  facet_wrap( ~ host_is_superhost)

As we can see from the above scatter plot, the more number of reviews the host can have, the more chances that the host will get higher Review score rating. In the mean time, if the host is a super host, the review score rating will be at least 80.

Review Score Rating vs Host Response Time

summary(airbnb_total$host_response_time)
                   a few days or more                N/A       within a day within a few hours 
                24               1871              17278               8984              11921 
    within an hour 
             23880 
summary(airbnb_total$review_scores_rating)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
   20.0    90.0    95.0    93.3   100.0   100.0   14325 
s <- subset(airbnb_total, host_response_time != 'N/A' & host_response_time !="")
  
ggplot(s, aes(review_scores_rating,colour = host_response_time)) +
  geom_density(size=1, show_guide=FALSE) +
  xlab("Review Scores Rating") +
  xlim(55, 100) +
  ggtitle("Distribution of Review Scores Rating by Response Time") +
       theme(plot.title = element_text(hjust = 0.5)) + 
  stat_density(aes(x=review_scores_rating, colour=host_response_time), geom="line", position="identity" )  +
  guides(colour = guide_legend(override.aes = list(size=2)))

As we can see from the multiple desnsity curves, there are quite a few people giving scores around 60 and 70. Very few people are giving scores under 60 so we eliminate the part under 50. A larger percentage of people starts to give scores at 80. Then it drops again. However, there’s a big difference in percentages when people give scores higher than 90 at the end of the plot. We can see that “a few days and more” are clearly lower than the other density curves. It may well indicate that people can certainly tolerant a response within a day. They may be indifferent with one hour or a day. But, if it’s beyond a day to repsond, the more probably that the host will not have higher score rating eventually.

Conclusion

There are several limitations in our current process. Firstly, the original datasets are not perfect. Certain features are not in earlier datasets, thus they are not consistent in variables. Datasets before Jan 2015 is rarely seen in the dataset lists. Secondly, no documentation is found along with the dataset. So we have to make an assumption on several features, such as availability_30, availability_60, availability_90, and availability_365. Thirdly, since we might lack continuous data on the price information, we cannot generate further exploratory analysis of price on a time series scale. Next, the dataset does not provide any data on the space size of the listing rentals. Most of the values are missing or equal to zero. We cannot make a further analysis on the listing price compared to the size of the space. Lastly, it does not provide neighbourhood_group_cleansed variable in Los Angeles. So it is hard to identify the correlation between room type, property type, minimum nights of stay and price , etc, within LA’s different neighborhoods. Different areas may have different result, like New York City. If those areas are hottest sightseeing or rich areas, the prices may reflect such distinctions.

In the future exploration, problems mentioned above should be fixed as much as possible. For example, it might be a great idea to do more cleaning work on the original dataset. We can clean the messy values in neighborhood variable in Los Angeles dataset with further knowledge in Los Angeles geographic information. With such clean values, we could further know how the price/review ratings/availabilities distributes in coordination with other variables. They may be affected by different potential factors within the zone. For another thing, we can switch our gear to check on the construction of score rating to know what travellers care most when they give a rating on Airbnb. There are many aspects can be improved in the future.

In this project, we get a touch of the real world data and have learned much during the process. Cleaning data is no doubt one very important part when you get hands down onto raw data.And to understand the meaning of each variable, to imagine the correlationship between variables, and to validate our assumptions using a suitable type of visualization are all precious experiences in this project. We tried different types of plots using the same variables to get the best results. That is what visualization needs in real data exploration.

Reproducibility

Download the datasets and with trivial file renaming, the code should be run without error. (with package installed) One thing to notice that, mosaic plot is an inserted image. If you change the code to show the mosaic plot. It will show the exactly same plot just without the x axis labels. It is a minor disfunction with ggmosaic. We change the labels under the instructors’s instruction.

All sources are cited with links.

LS0tCmh0bWxfZG9jdW1lbnQ6IAp0aXRsZTogIldlIEhvc3QgwrcgV2UgQm9vayDCtyBXZSBUcmF2ZWwiCnN0dWRlbnQ6IFlhbmcgIEdhbyAoeWcyNDk5KQogICAgICAgICBIYW9ibyBNYSAgKGhtMjY5MCkgIAogICAgICAgICBYaW4gICBMaXUgKHhsMjYyMikgCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKIyMjIyBHcm91cCBOYW1lOiBSZW50b2xvZ3kKIyMjIyBQcm9qZWN0IE5hbWU6IFZpc3VhbGl6ZSBBaXJibmIgUmVudGFscyBpbiBOZXcgWW9yayBDaXR5IGFuZCBMb3MgQW5nZWxlcwojIyMjIFN0dWRlbnQgTmFtZToKWWFuZyBHYW8gKHlnMjQ5OSksIEhhb2JvIE1hIChobTI2OTApLCBYaW4gTGl1ICh4bDI2MjIpIAoKIyNJbnRyb2R1Y3Rpb24KCkFpcmJuYiBpcyBhIGNvbW11bml0eS1iYXNlZCBvbmxpbmUgcGxhdGZvcm0gcHJvdmlkaW5nIHZhY2F0aW9uIHJlbnRhbHMsIHNob3J0IHJlbnRhbHMgYWxvbmcgd2l0aCBtYW55IG90aGVyIHR5cGVzIG9mIHJlbnRhbHMgYWxsIGFyb3VuZCB0aGUgd29ybGQuIEl0IGlzIGEgZ3JlYXQgY2hvaWNlIHRvIGZpbmQgZ3JlYXQgcGxhY2UgdG8gbGl2ZSBpbiBhbmQgbGl2ZSBsaWtlIGEgbG9jYWwgcGVyc29uLiBJdCBjb25uZWN0cyBob3N0cyBhbmQgdHJhdmVsZXJzLCBmYWNpbGl0YXRpbmcgdGhlIHByb2Nlc3Mgb2YgcmVudGluZyB3aXRob3V0IGh1Z2UgZXhwZW5zZXMgYnV0IHdpdGggY29udmVuaWVuY2VzLiBNb3Jlb3ZlciwgaXQgY3VsdGl2YXRlcyBhIHNoYXJpbmctZWNvbm9teSBieSBhbGxvd2luZyBwcm9wZXJ0eSBvd25lcnMgdG8gcmVudCBvdXQgcHJpdmF0ZSBwcm9wZXJ0aWVzIHRvIGJlbmVmaXQgdGhlIHdob2xlIGNvbW11bml0eS4gICAKCkFpcmJuYiB3YXMgZm91bmRlZCBpbiAyMDA4IGFuZCBub3cgaXMgZXN0aW1hdGVkIGFyb3VuZCAyNS41IGJpbGxpb24gVVNELCB3aGljaCBpcyBhbW9uZyB0aGUgdG9wIHVuaWNvcm5zIGluIHRlY2ggd29ybGQuIFdpdGggc3VjaCBhbiBvdmVyd2hlbG1pbmdseSBwb3B1bGFyIHdlYnNpdGUsICB3ZSB3b3VsZCBsaWtlIHRvIGRpZyBpbiBpdHMgZGF0YXNldHMgYW5kIGV4cGxvcmUgd2hhdCBraW5kIG9mIHBhdHRlcm5zIHdpbGwgYXBwZWFyIG9uIHRoZSB2aXN1YWxpemF0aW9uLiBUaGUgcHJvamVjdCBpcyBtb3JlIHRoYW4gbGlrZWx5IHRvIHByb3ZpZGUgYW4gaW5zaWdodCBvbiB3aGF0IGludGVyZXN0aW5nIGZpbmRpbmdzIHdpbGwgc2hvdyBpbiB0aGUgbGlzdGluZyBwcmljZXMgdGhlIHJldmlldyBzY29yZXMsIGFuZCByZW50YWwgYXZhaWxhYmlsaXRpZXMsIGV0Yy4gSW4gc2hhcmluZy1lY29ub215IGJ1c2luZXNzIG1vZGVsLCB0aGlzIGluc2lnaHQgd2lsbCBzaGVkIGxpZ2h0IG9uIGZ1dHVyZSBleHBsb3JhdGlvbiBpbiB1c2VyIHByZWZlcmVuY2UsIHdoaWNoIGlzIHVuZG91YnRlZGx5IGhpZ2hseSB2YWx1YWJsZSB0byB0aGUgZmlybS4gICAKClRoZXJlIGFyZSBzZXZlcmFsIGludGVyZXN0aW5nIHF1ZXN0aW9ucyB0byBiZSBhbnN3ZXJlZCBpbiB0aGUgcHJvamVjdCBhcyBmb2xsb3dzLiBGaXJzdGx5LCB3ZSB3aWxsIGNoZWNrIHRoZSBtaXNzaW5nIHZhbHVlcyBpbiBkYXRhc2V0cyB3ZSBmb3VuZC4gVGhpcyB3aWxsIGVuYWJsZSB1cyB0byBmaWd1cmUgb3V0IHRoZSBxdWFsaXR5IG9mIG91ciBkYXRhLiBOZXh0LCB3ZSB3YW50IHRvIGV4cGxvcmUgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgcmVudGFsIHByaWNlcyBhY2NvcmRpbmcgdG8gdGhlaXIgY2l0aWVzLCB0aGVpciBuZWlnaGJvcmhvb2RzLCBhbmQgdGhlaXIgcm9vbSB0eXBlcy4gVGhlbiB3ZSB3b3VsZCBsaWtlIHRvIHNlZSBob3cgbWluaW11bSBuaWdodHMgcmVxdWlybWVudHMsIGF2YWlsYWJpbGl0aWVzIGFyZSBkaXN0cmlidXRlZCBpbiBkaWZmZXJlbnQgY2l0aWVzL3Jvb20gdHlwZXMuIEFsc28sIHRoaXMgbWF5IHNoZWQgbGlnaHQgb24gc29tZXRoaW5nIHBlb3BsZSBkaWQgbm90IG5vdGljZSBiZWZvcmUgZXNwZWNpYWxseSBpbiBtZXRyb3BvbGl0YW5zIGFzIHdlIHNlbGVjdGVkLiBNb3Jlb3Zlciwgd2Ugd291bGQgbGlrZSB0byBleHBsb3JlIGluIGRlcHRoIGhvdyBtYW55IGxpc3RpbmcgcmVzaWRlbmNlIGNvbnRyb2xsZWQgYnkgdGhlIHNhbWUgaG9zdC4gVGhpcyBtYXkgZW5saWdodGVuIHVzIG9uIGlmIHRoZXJlIGV4aXN0cyBhIGdyb3VwIG9mIHBlb3BsZSBkZXBlbmRpbmcgb24gcmVudGFscyBvZiBBaXJibmIuIElmIHNvLCB3ZSB3YW50IHRvIGtub3cgd2hhdCBhcmVhIHRoZSBsaXN0aW5ncyB3aWxsIGJlIGluLiBMYXN0bHksIHdlIHdvdWxkIGxpa2UgdG8gc2VlIHdoYXQgZmFjdG9ycyB0aGUgcmV2aWV3IHJhdGluZ3MgYXJlIGNvcnJlbGF0ZWQgd2l0aCBpbiBkYXRhc2V0LgoKV2UgZ2V0IHRoZSBkYXRhIGZyb20gW0luc2lkZUFpcmJuYl0oaHR0cDovL2luc2lkZWFpcmJuYi5jb20vZ2V0LXRoZS1kYXRhLmh0bWwpLiBXZSB3b3VsZCBsaWtlIHRvIHNlbGVjdCBzb21lIGJpZyBjaXRpZXMgc3VjaCBhcyBOZXcgWW9yayBDaXR5IGFuZCBMb3MgQW5nZWxlcyBpbiBVbml0ZWQgU3RhdGVzIGZvciB0aGlzIHByb2plY3QuIE9yaWdpbmFsIGRhdGFzZXRzIHdlcmUgY29tcGlsZWQgYnkgb24gTWFyY2ggMm5kIDIwMTcsIGNvbnRhaW5pbmcgbGlzdGluZ3Mgd2hpY2ggcHJvdmlkZXMgc3VtbWFyeSBpbmZvcm1hdGlvbiBhbmQgbWV0cmljcyBmb3IgbGlzdGluZ3MuIEFsbCBsaXN0aW5nIGZpbGVzIHNhdmVkIGFzIGNzdiBmb3JtYXQuIEFmdGVyIHByaW50aW5nIHNvbWUgc2FtcGxlcyBpbiB0aGUgb3JpZ2luYWwgZGF0YXNldHMsIHdlIHRoaW5rIHRoYXQgdGhpcyB3ZWJzaXRlIHNlZW1zIHRvIHByb3ZpZGUgcXVpdGUgbmV3IGRhdGFzZXRzIGFuZCBrZWVwcyBhbiBvcmlnaW5hbCB0b3VjaCBvZiBkYXRhLiAgCgpUaGUgcmF3IGxpc3RpbmcgZGF0YXNldHMgY29udGFpbiA5NSB2YXJpYWJsZXMgYW5kIGhhdmUgZGlmZmVyZW50IGRhdGEgdHlwZXMuIFRoZSBkYXRhc2V0cyByZWNvcmQgaW5mb3JtYXRpb24gYWJvdXQgaG9zdHMgYW5kIHRoZWlyIHJlbnRhbCBsaXN0aW5ncywgd2hpY2ggaXMgbW9zdGx5IGxpa2VseSB0byBiZSBzY3JhcGVkIGZyb20gQWlyYm5iIHdlYnNpdGUgZGlyZWN0bHkgKEFpcmJuYiBkb2VzIG5vdCByZWxlYXNlIG9mZmljaWFsIGRhdGFzZXRzLCB0aG91Z2ggdGhlcmUgYXJlIGEgcGxlbnR5IG9mIHVub2ZmaWNpYWwgZGF0YSBzb3VyY2VzKS4gVGhlIHJhdyBkYXRhc2V0IGluY2x1ZGVzIGhvc3QgaW5mb3JtYXRpb24gc3VjaCBhcyBob3N0IGlkLCByZW50YWwgbGlzdGluZyBkZXNjcmlwdGlvbiwgbmVpZ2hib3VyaG9vZCwgcHJvcGVydHkgdHlwZSwgcm9vbSB0eXBlLCBtaW5pbXVtIG5pZ2h0cyB0byBzdGF5LHJldmlldyBzY29yZXMsIHByaWNlLCBldGMuIAoKWW91IGNhbiBlYXNpbHkgZG93bmxvYWQgdGhlIGRhdGFzZXQgZnJvbSB0aGUgd2Vic2l0ZSBsaXN0ZWQgaW4gdGhlIHByZXZpb3VzIHBhcmFncmFwaC4gRm9yIGVhY2ggY2l0eSwgeW91IGNhbiBjbGljayBidXR0b24gdG8gc2VlIG1vcmUgZGF0YXNldCBzaG93aW5nLgoKIyNUZWFtIE1lbWJlcnMgRGVzY3JpcHRpb24KCkFsbCB0aGUgdGVhbSBtZW1iZXJzIHRha2UgY2FyZSBvZiBkYXRhIGNsZWFuaW5nIHN0ZXBzLCB0cmFuc2ZlcnJpbmcgcmF3IGRhdGEgaW50byB0aWR5IGRhdGFzZXQuIFdlIGRpc2N1c3MgYWJvdXQgdGhlIHZhcmlhYmxlcyB3ZSBuZWVkIGFuZCB3b3JrIHRvZ2V0aGVyLiBPbmNlIGFsbCBkYXRhIGNsZWFuaW5nIGlzIGNvbXBsZXRlLCB3ZSBtb3ZlIG9uIHRvIGNyZWF0ZSB2aXN1YWxpemF0aW9uIHBsb3RzLiAKClRvIGdlbmVyYXRlIHRoZSB2aXN1YWxpemF0aW9uIHBsb3RzLCBZYW5nIHdpbGwgY3JlYXRlIFNjYXR0ZXJwbG90IChiYXNlZCBvbiBnZW9ncmFwaGljIGRpbWVuc2lvbnMpLCBCYXIgQ2hhcnRzLCBIaXN0b2dyYW0sVGltZSBTZXJpZXMgYW5kIERlbnNpdHkgUGxvdHM7IEhhb2JvIHdpbGwgY3JlYXRlIHRleHQgbWluaW5nIGFuZCBkZXNpZ24gdGhlIFdvcmxkQ2xvdWQgYXMgd2VsbCBhcyB0aGUgTWlzc2luZyBWYWx1ZSBoZWF0bWFwIHBsb3RzOyBQYXJhbGxlbCBDb29yZGluYXRlIFBsb3QgYW5kIE1vc2FpYyB3aWxsIGJlIGNyZWF0ZWQgYnkgWGluLgoKSW4gdGhlIHJlcG9ydCB3cml0aW5nLCBlYWNoIG9mIHVzIHdpbGwgYmUgcmVzcG9uc2libGUgZm9yIG93biB2aXN1YWxpemF0aW9ucyBpbiB0aGUgbWFpbiBhbmFseXNpcy4gV2Ugd2lsbCBpbnRlZ3JhdGUgb3VyIGZpbmRpbmdzIGFuZCB2aXN1YWxpemF0aW9uIGdyYXBoaWNzIHRvZ2V0aGVyLiBXZSB3b3JrIHRvZ2V0aGVyIG9uIEludHJvZHVjdGlvbiBhbmQgbGltaXRhdGlvbnMgaW4gY29uY2x1c2lvbi4gWWFuZyBhbmQgSGFvYm8gYXJlIGFsc28gd29ya2luZyBvbiBgSW50cm9kdWN0aW9uYCwgYEFuYWx5c2lzIG9mIERhdGEgUXVhbGl0eWAgYW5kIGBNYWluIEFuYWx5c2lzYC4gIFhpbiBpcyBmb3IgYEV4ZWN1dGl2ZSBzdW1tYXJ5YCBhbmQgYENvbmNsdXNpb25gLiBMYXN0IGJ1dCBub3QgbGVhc3QsIHRoZSB3aG9sZSB0ZWFtIHdvcmsgdG9nZXRoZXIgdG8gZmluYWxpemUgdGhlIHByb2plY3QgcmVwb3J0LgoKIyNBbmFseXNpcyBvZiBEYXRhIFF1YWxpdHkKYGBge3IsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KbGlicmFyeShnZ21hcCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeShleHRyYWNhdCkKbGlicmFyeShnZ21vc2FpYykKbGlicmFyeShtaSkKYGBgCgojIyNMb2FkIERhdGFzZXRzCmBgYHtyLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiNzZXR3ZCgiL1VzZXJzL2dhb3lhbmcvRGVza3RvcC9maW5hbCIpCmxpc3QwMzE3X255IDwtIHJlYWQuY3N2KCIvVXNlcnMvS2V2aW5zbmFwc2hvdy9Db2x1bWJpYSBVbml2ZXJzaXR5IEVtYWlsL0VEVi9EYXRhL05ZQy9NYXJjaF8yMDE3L2xpc3RpbmdzLXJhdy5jc3YiLAogICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFKQpsaXN0MDMxN19sYSA8LSByZWFkLmNzdigiL1VzZXJzL0tldmluc25hcHNob3cvQ29sdW1iaWEgVW5pdmVyc2l0eSBFbWFpbC9FRFYvRGF0YS9MQS8wM18yMDE3L2xpc3RpbmdzLXJhdy5jc3YiLAogICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFKQpsaXN0MDMxN19ueSRjaXR5X25hbWUgPC0gIk5ldyBZb3JrIENpdHkiCmxpc3QwMzE3X2xhJGNpdHlfbmFtZSA8LSAiTG9zIEFuZ2VsZXMiCgoKI3N0YWNrIHJhdyBkYXRhc2V0cyhzdGFjayB2ZXJ0aWNhbGx5KQphaXJibmJfdG90YWwgPC0gcmJpbmQobGlzdDAzMTdfbnksIGxpc3QwMzE3X2xhKQphaXJibmJfdG90YWwkY291bnQgPC0xCmFpcmJuYl90b3RhbCRwcmljZSA8LSBhcy5udW1lcmljKGdzdWIoIlxcJCIsICIiLCBhaXJibmJfdG90YWwkcHJpY2UpKQphaXJibmJfdG90YWxfMiA8LSBzdWJzZXQoYWlyYm5iX3RvdGFsLHNlbGVjdCA9IGMoaG9zdF9zaW5jZSxjb3VudCxjaXR5X25hbWUpKQpgYGAKCiMjI01pc3NpbmcgRGF0YSBBbmFseXNpcwpUaGUgd2hvbGUgZGF0YXNldHMgaGF2ZSBtYW55IGRpZmZlcmVudCBkYXRhIHR5cGVzLCBhbmQgaGF2ZSBtb3JlIHRoYW4gNTAlIHZhbHVlcyBpbiBjYXRlZ29yaWNhbCBkYXRhLiBXZSB3YW50IHRvIGNoZWNrIGhvdyBtaXNzaW5nIHZhbHVlcyBhcmUgc3ByZWFkIGluIHRoaXMgZGF0YXNldC4gSGVyZSB3ZSBjaG9vc2UgdHdvIGRpZmZlcmVudCBtZXRob2RzLiBGaXJzdCBpcyB0byBsb2FkIHRoZSBleHRyYWNhdCBsaWJyYXJ5IGFuZCB1c2UgdGhlIHZpc25hIGZ1bmN0aW9uIHRvIHVuY292ZXIgYWxsIHRoZSBjb21iaW5hdGlvbnMgdGhhdCBoYXZlIG1pc3NpbmcgdmFsdWVzLiBTZWNvbmQgaXMgdGhlIHRvIGxvYWQgdGhlIG1pIHBhY2thZ2UgYW5kIHVzZSB0aGUgaW1hZ2UgZnVuY3Rpb24gdG8gcGxvdCB0aGUgaGVhdG1hcC1saWtlIHBsb3Qgb2YgdGhlIG1pc3NpbmcgdmFsdWVzLiBXZSBiZWdpbiB3aXRoIHNlbGVjdGluZyB0aGUgdXNlZnVsIHZhcmlhYmxlcyB3aGljaCBhcmUgcHJvYmFibHkgdG8gYmUgdXNlZCBmb3IgZnVydGhlciBhbmF5c2lzIGZyb20gdGhlIG9yaWdpbmFsIGRhdGFzZXQsIGZyb20gYm90aCBOWUMgYW5kIExBIGRhdGFzZXRzLiBUaGUgZGV0YWlscyBhcmUgc2hvd24gaW4gdGhlIGZvbGxvd2luZyBwbG90czoKCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KY29tcGFyZU5BIDwtIGZ1bmN0aW9uKHYxLHYyKSB7CiAgICAjIFRoaXMgZnVuY3Rpb24gcmV0dXJucyBUUlVFIHdoZXJldmVyIGVsZW1lbnRzIGFyZSB0aGUgc2FtZSwgaW5jbHVkaW5nIE5BJ3MsCiAgICAjIGFuZCBmYWxzZSBldmVyeXdoZXJlIGVsc2UuCiAgICBzYW1lIDwtICh2MSA9PSB2MikgIHwgIChpcy5uYSh2MSkgJiBpcy5uYSh2MikpCiAgICBzYW1lW2lzLm5hKHNhbWUpXSA8LSBGQUxTRQogICAgcmV0dXJuKHNhbWUpCiAgIH0KCm1pc3NpbmdkYXRhX255IDwtIGxpc3QwMzE3X255WzE6MTAwMCxjKDEsNTo4LDEwOjE1LDIwLDIyLDIzLDI1LDI2LDI5LDM1LDM3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNDAsNDEsNDksNTAsNTIsNTMsNjEsNjgsNzUsNzcsODAsOTEsOTUsOTYpXSAKbWlzc2luZ2RhdGFfbGEgPC0gbGlzdDAzMTdfbGFbMToxMDAwLGMoMSw1OjgsMTA6MTUsMjAsMjIsMjMsMjUsMjYsMjksMzUsMzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA0MCw0MSw0OSw1MCw1Miw1Myw2MSw2OCw3NSw3Nyw4MCw5MSw5NSw5NildIAoKI05ldyBZb3JrIENpdHkgbWlzc2luZyBkYXRhCm1pc3NpbmdkYXRhX255XzEgPC0gbWlzc2luZ2RhdGFfbnkgCmlzLm5hKG1pc3NpbmdkYXRhX255XzEpIDwtIG1pc3NpbmdkYXRhX255XzEgPT0nJyAjY2hhbmdlIGJsYW5rIGNlbGxzIGludG8gTkEKaXMubmEobWlzc2luZ2RhdGFfbnlfMSkgPC0gbWlzc2luZ2RhdGFfbnlfMSA9PSdOQScgI05BCnZpc25hKG1pc3NpbmdkYXRhX255XzEsIHNvcnQgPSAiYiIsc29ydC5tZXRob2QgPSAiY291bnQiLCBmcj01MCwgcG1heCA9IDAuMDUscyA9MikKaW1hZ2UobWlzc2luZ19kYXRhLmZyYW1lKG1pc3NpbmdkYXRhX255XzEpKQoKI0xvcyBBbmdlbGVzIG1pc3NpbmcgZGF0YQptaXNzaW5nZGF0YV9sYV8xIDwtIG1pc3NpbmdkYXRhX2xhCmlzLm5hKG1pc3NpbmdkYXRhX2xhXzEpIDwtIG1pc3NpbmdkYXRhX2xhXzEgPT0nJyAjY2hhbmdlIGJsYW5rIGNlbGxzIGludG8gTkEKaXMubmEobWlzc2luZ2RhdGFfbGFfMSkgPC0gbWlzc2luZ2RhdGFfbGFfMSA9PSdOQScgI05BCnZpc25hKG1pc3NpbmdkYXRhX2xhXzEsIHNvcnQgPSAiYiIsc29ydC5tZXRob2QgPSAiY291bnQiLCBmcj01MCxwbWF4ID0gMC4wNSxzID0yKQppbWFnZShtaXNzaW5nX2RhdGEuZnJhbWUobWlzc2luZ2RhdGFfbGFfMSkpCmBgYAoKRnJvbSBwbG90cyBhYm92ZSwgd2UgY2FuIGVhc2lseSBzZWUgdGhlIHBlcmNlbnRhZ2Ugb2YgbWlzc2luZyB2YWx1ZXMgaW4gdGhvc2UgdmFyaWFibGVzLiBXZSB3aWxsIHRha2UgY2FyZSBvZiB0aG9zZSBtaXNzaW5nIHZhbHVlcyBpbiBmdXJ0aGVyIGFuYWx5c2lzLiBEdWUgdG8gdGhlIGxvY2FsIG1hY2hpbmUgY2FwYWJpbGl0eSwgdGhlIHBsb3RzIGFyZSBnZW5lcmF0ZWQgYnkgc3Vic2V0dGluZyBzYW1wbGVzIGZyb20gb3JpZ2luYWwgZGF0YXNldHMuCgpJbiBhZGRpdGlvbiB0byB0aGUgbWlzc2luZyB2YWx1ZXMsIHdlIGFsc28gZmluZCB0aGF0IHRoZXJlIGFyZSBzZXZlcmFsIGNvbHVtbnMgZnVsbCBvZiBzdHJpbmdzL3dvcmRzLiBXZSBjaG9vc2UgdG8gaW1wbGVtZW50IHRleHQgbWluaW5nIHRlY2huaWNzIG9uIHRob3NlIGNvbHVtbnMgYWxvbmcgd2l0aCBXb3JkQ2xvdWQgdG8gZXhwbG9yZSBtb3JlIGFuYWx5dGljYWwgYW5hbHlzaXMgb24gY3VzdG9tZXJzIGJlaGF2aW9yLiBXZSB3aWxsIGlubGN1ZGUgbW9yZSBkZXRhaWxzIGluIEV4ZWN1dGl2ZSBTdW1tYXJ5IHNlc3Npb24uCk92ZXJhbGwsIHRoZSBkYXRhIHF1YWxpdHkgc2VlbXMgZ29vZCBmb3Igb3VyIHJlc2VhcmNoIGFuZCBhbmFseXNpcyBwdXJwb3Nlcy4gIAoKIyNFeGVjdXRpdmUgU3VtbWFyeSAKCiMjI1RpbWUgU2VyaWVzIFBsb3Qgb2YgQWlyYm5iIEhvc3QgUmVnaXN0ZXIgaW4gTmV3IFlvcmsgQ2l0eSB2cyBMb3MgQW5nZWxlcwpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiN0aW1lIHNlcmllcyBwbG90CiNwbG90IDEKYWlyYm5iX3RvdGFsXzIgPC0gc3Vic2V0KGFpcmJuYl90b3RhbCxzZWxlY3QgPSBjKGhvc3Rfc2luY2UsY291bnQsY2l0eV9uYW1lKSkKaDEgPC0gYWlyYm5iX3RvdGFsXzIgJT4lIAogIHNlbGVjdChob3N0X3NpbmNlLGNvdW50LGNpdHlfbmFtZSkgJT4lCiAgZ3JvdXBfYnkoaG9zdF9zaW5jZSxjaXR5X25hbWUpICU+JQogIHN1bW1hcmlzZShUb3RhbF9Db3VudCA9c3VtKGNvdW50LG5hLnJtPVRSVUUpKSAKCmgyIDwtIHN1YnNldChoMSxob3N0X3NpbmNlICE9IiIpICNyZW1vdmUgbWlzc2luZyB2YWx1ZQpoMiRkYXRlIDwtIGZvcm1hdChhcy5EYXRlKGgyJGhvc3Rfc2luY2UpLCAiJW0vJVkiKQpoMiR5ZWFyIDwtIGdzdWIoIi4qLyIsIiIsaDIkZGF0ZSkKCiMgY2hhbmdlIGNhdGVnb3JpY2FsIHZhcmlhYmxlCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzAzLzIwMDgnKV0gPC0gIjIwMDggUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMDgnLCcwNS8yMDA4JywnMDYvMjAwOCcpXSA8LSAiMjAwOCBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAwOCcsJzA4LzIwMDgnLCcwOS8yMDA4JyldIDwtICIyMDA4IFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDA4JywnMTEvMjAwOCcsJzEyLzIwMDgnKV0gPC0gIjIwMDggUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDA5JywnMDIvMjAwOScsJzAzLzIwMDknKV0gPC0gIjIwMDkgUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMDknLCcwNS8yMDA5JywnMDYvMjAwOScpXSA8LSAiMjAwOSBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAwOScsJzA4LzIwMDknLCcwOS8yMDA5JyldIDwtICIyMDA5IFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDA5JywnMTEvMjAwOScsJzEyLzIwMDknKV0gPC0gIjIwMDkgUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDEwJywnMDIvMjAxMCcsJzAzLzIwMTAnKV0gPC0gIjIwMTAgUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMTAnLCcwNS8yMDEwJywnMDYvMjAxMCcpXSA8LSAiMjAxMCBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAxMCcsJzA4LzIwMTAnLCcwOS8yMDEwJyldIDwtICIyMDEwIFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDEwJywnMTEvMjAxMCcsJzEyLzIwMTAnKV0gPC0gIjIwMTAgUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDExJywnMDIvMjAxMScsJzAzLzIwMTEnKV0gPC0gIjIwMTEgUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMTEnLCcwNS8yMDExJywnMDYvMjAxMScpXSA8LSAiMjAxMSBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAxMScsJzA4LzIwMTEnLCcwOS8yMDExJyldIDwtICIyMDExIFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDExJywnMTEvMjAxMScsJzEyLzIwMTEnKV0gPC0gIjIwMTEgUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDEyJywnMDIvMjAxMicsJzAzLzIwMTInKV0gPC0gIjIwMTIgUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMTInLCcwNS8yMDEyJywnMDYvMjAxMicpXSA8LSAiMjAxMiBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAxMicsJzA4LzIwMTInLCcwOS8yMDEyJyldIDwtICIyMDEyIFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDEyJywnMTEvMjAxMicsJzEyLzIwMTInKV0gPC0gIjIwMTIgUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDEzJywnMDIvMjAxMycsJzAzLzIwMTMnKV0gPC0gIjIwMTMgUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMTMnLCcwNS8yMDEzJywnMDYvMjAxMycpXSA8LSAiMjAxMyBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAxMycsJzA4LzIwMTMnLCcwOS8yMDEzJyldIDwtICIyMDEzIFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDEzJywnMTEvMjAxMycsJzEyLzIwMTMnKV0gPC0gIjIwMTMgUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDE0JywnMDIvMjAxNCcsJzAzLzIwMTQnKV0gPC0gIjIwMTQgUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMTQnLCcwNS8yMDE0JywnMDYvMjAxNCcpXSA8LSAiMjAxNCBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAxNCcsJzA4LzIwMTQnLCcwOS8yMDE0JyldIDwtICIyMDE0IFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDE0JywnMTEvMjAxNCcsJzEyLzIwMTQnKV0gPC0gIjIwMTQgUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDE1JywnMDIvMjAxNScsJzAzLzIwMTUnKV0gPC0gIjIwMTUgUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMTUnLCcwNS8yMDE1JywnMDYvMjAxNScpXSA8LSAiMjAxNSBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAxNScsJzA4LzIwMTUnLCcwOS8yMDE1JyldIDwtICIyMDE1IFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDE1JywnMTEvMjAxNScsJzEyLzIwMTUnKV0gPC0gIjIwMTUgUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDE2JywnMDIvMjAxNicsJzAzLzIwMTYnKV0gPC0gIjIwMTYgUTEiCmgyJHF1YXJbaDIkZGF0ZSAlaW4lIGMoJzA0LzIwMTYnLCcwNS8yMDE2JywnMDYvMjAxNicpXSA8LSAiMjAxNiBRMiIKaDIkcXVhcltoMiRkYXRlICVpbiUgYygnMDcvMjAxNicsJzA4LzIwMTYnLCcwOS8yMDE2JyldIDwtICIyMDE2IFEzIgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcxMC8yMDE2JywnMTEvMjAxNicsJzEyLzIwMTYnKV0gPC0gIjIwMTYgUTQiCgpoMiRxdWFyW2gyJGRhdGUgJWluJSBjKCcwMS8yMDE3JywnMDIvMjAxNycsJzAzLzIwMTcnKV0gPC0gIjIwMTcgUTEiCgpoMyA8LSBoMiAlPiUgCiAgc2VsZWN0KHF1YXIsVG90YWxfQ291bnQsY2l0eV9uYW1lKSAlPiUKICBncm91cF9ieShxdWFyLGNpdHlfbmFtZSkgJT4lCiAgc3VtbWFyaXNlKENvdW50ID1zdW0oVG90YWxfQ291bnQsbmEucm09VFJVRSkpIAoKaGVhZChoMywxMCkKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CmdncGxvdChzdWJzZXQoaDMscXVhciAhPSIyMDE3IFExIiksIGFlcyhxdWFyLCBDb3VudCxncm91cCA9Mixjb2xvciA9Y2l0eV9uYW1lKSkgKyAKICBnZW9tX2xpbmUoYWVzKGdyb3VwID1jaXR5X25hbWUpLCBzaXplID0yKSArCiAgeGxhYigiUXVhcnRlciAoWWVhcikiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT04LCBhbmdsZSA9NDAsIGhqdXN0ID0gMSkpICsKICBnZ3RpdGxlKCJBaXJibmIgSG9zdCBSZWdpc3RlciBpbiBOZXcgWW9yayBDaXR5IFZTIExvcyBBbmdlbGVzICgyMDA4IC0gMjAxNikiKSArCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIGdlb21fdGV4dChkYXRhPXN1YnNldChoMyxxdWFyICE9IjIwMTcgUTEiKVtjKDMzLDM0LDQxLDQyLDQ5LDUwLDU3LDU4LDY1LDY2LDczLDc0KSxdLCBsYWJlbD0iUTEiLHZqdXN0ID0xLCBzaXplID00KQpgYGAKQXMgbWVudGlvbmVkIGluIHRoZSBpbnRyb2R1Y3Rpb24sIEFpcmJuYiBpcyBib29taW5nIGluIHJlY2VudCB5ZWFycyBhbmQgYXR0cmFjdGluZyBtb3JlIGFuZCBtb3JlIG5ldyB1c2VycyBhbGwgYXJvdW5kIHRoZSB3b3JsZC4gU28gdGhlIGZpcnN0IHBsb3QgcHJlc2VudGVkIGhlcmUgaXMgdGhlIHRpbWUgc2VyaWVzIGN1cnZlIGZvciBuZXcgcmVnaXN0ZXJzIGluIE5ldyBZb3JrIENpdHkgYW5kIExvcyBBbmdlbGVzIGZyb20gMjAwOChmb3VuZGVkKSB0byAyMDE2LiBUaGUgWCBheGlzIGlzIG1lYXN1cmVkIGluIHF1YXJ0ZXJzIGFuZCB5b3UgY2FuIGVhc2lseSBzZWUgdGhlIHRyZW5kIGlzIGdyb3dpbmcgcmFwaWRseSBzdGFydGluZyBmcm9tIDIwMTAgUTEuIFRob3VnaCB0aGVyZSBhcmUgY2xlYXIgZG93bmZhbGxzIGluIDIwMTIgUTEgLCAyMDEzIFExICwgMjAxNCBRMSBpbiBOZXcgWW9yayAoMjAxMyBRNCBpbiBMb3MgQW5nZWxlcykgYW5kIDIwMTUgUTEgaW4gTmV3IFlvcmsgKDIwMTQgUTQgaW4gTG9zIEFuZ2VsZXMpLCBlc3BlY2lhbGx5IGluIDIwMTQsIHRoZSBnZW5lcmFsIHRyZW5kIGlzIHlldCB1bmRvdWJ0ZWRseSBhbiBpbmNyZWFzaW5nIG9uZS4KClRoZSB2ZXJ5IGludHJpZ3VpbmcgZmluZGluZyBpcyBkZWNyZWFzaW5nIHBhdHRlcm4gZm9yIFExLCBhcyBtYXJrZWQgaW4gcGxvdC4gVGhlIHBhdHRlcm4gbWF5IGJlIGFuc3dlcmVkIGJ5IG1vcmUgcHJvZmVzc2lvbmFsIGJ1c2luZXNzIGluc2lkZXJzLiBRMSAoc29tZXRpbWVzIFE0IGl0IGRlcGVuZHMpIG1pZ2h0IGJlIGEgYmFkIHF1YXJ0ZXIgZm9yIGJ1c2luZXNzIGluIGdlbmVyYWwgb3Igc28uIE5vdyB3aGF0IHdlIGNhcmUgbW9yZSBpcyB0aGF0IHRoZSB2ZXJ5IHN0ZWVwIGZhbGwgaW4gTG9zIEFuZ2VsZXMgMjAxNiBRNC4gVGhlIGRyb3AgaXMgc28gbGFyZ2UgdGhhdCB3ZSBuZWFybHkgc3VzcGVjdCB0aGF0IGRhdGEgaXMgc29tZWhvdyB3cm9uZyBpbiB0aGlzIHF1YXJ0ZXIuIEhvd2V2ZXIsIHdlIGZvdW5kIHRoaXMgbmV3czogW0wuQS4gSXMgUG9pc2VkIHRvIEVuYWN0IFN0cmljdCBBaXJibmIgUmVndWxhdGlvbnNdKGh0dHA6Ly93d3cubGF3ZWVrbHkuY29tL25ld3MvbGEtaXMtcG9pc2VkLXRvLWVuYWN0LXN0cmljdC1haXJibmItcmVndWxhdGlvbnMtNzA1NjEwNSksIHRoZSBzdHJpY3QgcmVndWxhdGlvbnMgbWF5IGV4cGxhaW4gd2h5IEFpcmJuYiBpcyBleHBlcmllbmNpbmcgYSBmaWVyY2Ugd2ludGVyIGluIExvcyBBbmdlbGVzLiBTbyBub3csIHdlIGhhdmUgYWxyZWFkeSBsZWFybmVkIGEgYmFzaWMgaWRlYSBhYm91dCBBaXJibmIuCiAgCiMjI0JveHBsb3Qgb2YgQWlyYm5iIFJlbnRhbCBQcmljZSBpbiBOZXcgWW9yayBDaXR5IHZzIExvcyBBbmdlbGVzCgpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiNib3hwbG90IE5ZQyB2cyBMQQojcGxvdCAyCmFpcmJuYl90b3RhbF8zIDwtIHN1YnNldChhaXJibmJfdG90YWwsIHByaWNlIDw9IDUwMCkKZ2dwbG90KHN1YnNldChhaXJibmJfdG90YWxfMyksIGFlcyh4PXJvb21fdHlwZSwgeT1wcmljZSwgZmlsbD1jaXR5X25hbWUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHhsYWIoIlJvb20gVHlwZSIpICsKICB5bGFiKCJQcmljZSBpbiBEb2xsYXJzIChVU0QpIikgKwogIGdndGl0bGUoIlByaWNlIEJ5IFJvb20gVHlwZSBpbiBOZXcgWW9yayBDaXR5IFZzIExvcyBBbmdlbGVzIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKYGBgCkFmdGVyIGNoZWNraW5nIHRoZSBuZXcgcmVnaXN0ZXJzIGZvciBBaXJibmIsIHdlIHRoZW4gbG9vayBjbG9zZXIgYXQgaG93IHRoZSBwcmljZXMgZGlzdHJpYnV0ZSBpbiBOZXcgWW9yayBDaXR5IGFuZCBMb3MgQW5nZWxlcy4gQSBtdWx0aXBsZSBib3gtcGxvdCBpcyBleHBsb2l0ZWQgaGVyZS4gSXQgdXRpbGl6ZWQgbm90IG9ubHkgdGhlIHByaWNlIHZhcmlhYmxlLCBidXQgYWxzbyB0aGUgcm9vbSB0eXBlcy4gIAoKV2Ugd2FudCB0byBhZGRyZXMgdGhhdCB3ZSBmaWx0ZXIgb3V0IGFsbCB0aGUgbGlzdGluZ3MgdGhhdCBhcmUgaGlnaGVyIHRoYW4gNTAwIGRvbGxhcnMgc2luY2UgdGhleSBhcmUgb2J2aW91cyBvdXRsaWVycyBpbiBoaXN0b2dyYW0sIHdoaWNoIHdpbGwgYmUgbWVudGlvbmVkIGluIG1haW4gYW5hbHlzaXMuIFRvIGFjaGlldmUgYSBiZXR0ZXIgdmlzdWFsaXphaXRvbiBvZiBwcmljZXMsIHdlIHdhbnQgdG8ga2VwcCB0aGUgcHJpY2VzIHVuZGVyIDUwMC4gV2l0aCBhZnRlci1maWx0ZXJpbmcgZGF0YSwgd2UgY29uc3RydWN0IHRoaXMgYm94LXBsb3QuICAKClRoZSBmaXJzdCBpbXByZXNzaW9uIGlzIHRoYXQgcHJpY2VzIGluIE5ldyBZb3JrIENpdHkgaXMgZ2VuZXJhbGx5IGhpZ2hlciB0aGFuIHRob3NlIGluIExvcyBBbmdlbGVzLiBBbGwgdGhyZWUgTlkgYm94ZXMgYXJlIGhpZ2hlciB0aGFuIExBIG9uZXMuIEl0IHNob3dzIHRoYXQgcHJpY2VzIGZvciBlYWNoIHJvb20gdHlwZSwgTlkgaXMgZ2VuZXJhbGx5IGhpZ2hlci4gU3BlY2lmaWNhbGx5LCBwcmljZXMgYXJlIGFsbW9zdCB0aGUgc2FtZSBmb3IgcHJpdmF0ZSByb29tLiBGb3IgZW50aXJlIGhvbWUvYXB0LCBOWSBib3ggaXMgY2xlYXJseSBoaWdoZXIgdGhhbiBMQSwgQXMgZm9yIHNoYXJlZCByb29tLCBOWSBib3ggaXMgbXVjaCBoaWdoZXIgdGhhbiBMQSBvbmUuIFRoZSBkaXN0aW5jdGlvbiBiZXR3ZWVuIHJvb20gdHlwZXMgYXJlIG5ldyBmaW5kaW5ncy4gICAgICAKCk5leHQsIHdlIGFyZSBub3Qgc3VycHJpc2VkIHRvIHNlZSB0aGF0IHRoZXJlIGFyZSBzdGlsbCBhIGxhcmdlIGFtb3VudCBvZiBvdXRsaWVycyBpbiBoaWdoZXIgcHJpY2UgbGV2ZWwuIEJ1dCBsb29rIGF0IHRoZSBkZXRhaWxzIGhlcmUuIEZvciBzaGFyZWQgcm9vbXMsIHRoZSBvdXRsaWVycyBhcmUgc3BhcnNlLiBGb3IgcHJpdmF0ZSByb29tLCB0aGUgb3V0bGllcnMgc2VlbXMgdG8gYmVjb21lIG1vcmUuIEFuZCBib3RoIG9mIHRoZW0gaGF2ZSByZWxhdGl2ZWx5IHNob3J0IHdoaXNrZXJzLiBXaGVuIGl0IGNvbWVzIHRvIGVudGlyZSBob21lL2FwdCwgaXQgaGFzIGxvbmcgd2hpc2tlcnMgYW5kIGEgbG90IG9mIG91dGxpZXJzLiBXZSBjYW4gZWFzaWx5IGFzc3VtZSB0aGF0IGVudGlyZSBob21lL2FwdCBhcmUgdmFyaW5nIGEgbG90IGluIHByaWNlIGFuZCBpdCBnZXRzIHRoZSBoaWdoZXN0IGxpc3RpbmcgcHJpY2UgaW4gd2hvbGUgZGF0YXNldC4gQW5kIGl0IGlzIHJlYXNvbmFsZSBmaW5kaW5nIHRoYXQgb25lIGVudGlyZSBob21lL2FwdCBjYW4gYmUgdmVyeSBleHBlbnNpZSBpbiBOWUMvTEEuCiAgCiMjI1dvcmQgQ2xvdWQgRGlzY292ZXJ5CiAgCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KI3dvcmQgY291bnQKI3Bsb3QgMwoKI05ZQyB3b3JkIGNvdW50cwpoMl9ueSA8LXN1YnNldChsaXN0MDMxN19ueSwgc2VsZWN0PWMoInN1bW1hcnkiLCJkZXNjcmlwdGlvbiIsIm5laWdoYm9yaG9vZF9vdmVydmlldyIsIm5vdGVzIiwidHJhbnNpdCIsInByaWNlIiwiYWNjZXNzIiwiaW50ZXJhY3Rpb24iKSkKCmgyX255X21lcmdlPC0gZG8uY2FsbChwYXN0ZTAsIGxpc3QwMzE3X255W2MoInN1bW1hcnkiLCJkZXNjcmlwdGlvbiIsIm5laWdoYm9yaG9vZF9vdmVydmlldyIsIm5vdGVzIiwidHJhbnNpdCIsInByaWNlIiwiYWNjZXNzIiwiaW50ZXJhY3Rpb24iKV0pCgpoMl9ueV91bmlvbj1oMl9ueV9tZXJnZVtzYW1wbGUobGVuZ3RoKGgyX255X21lcmdlKSw2MDAwKV0KCmRvY3NfbnkgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShoMl9ueV91bmlvbikpCnRvU3BhY2UgPC0gY29udGVudF90cmFuc2Zvcm1lcihmdW5jdGlvbiAoeCAsIHBhdHRlcm4gKSBnc3ViKHBhdHRlcm4sICIgIiwgeCkpCmRvY3NfbnkgPC0gdG1fbWFwKGRvY3NfbnksIHRvU3BhY2UsICIvIikKZG9jc19ueSA8LSB0bV9tYXAoZG9jc19ueSwgdG9TcGFjZSwgIkAiKQpkb2NzX255IDwtIHRtX21hcChkb2NzX255LCB0b1NwYWNlLCAiXFx8IikKZG9jc19ueSA8LSB0bV9tYXAoZG9jc19ueSwgY29udGVudF90cmFuc2Zvcm1lcih0b2xvd2VyKSkKIyBSZW1vdmUgbnVtYmVycwpkb2NzX255IDwtIHRtX21hcChkb2NzX255LCByZW1vdmVOdW1iZXJzKQojIFJlbW92ZSBlbmdsaXNoIGNvbW1vbiBzdG9wd29yZHMKZG9jc19ueSA8LSB0bV9tYXAoZG9jc19ueSwgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQojIFJlbW92ZSB5b3VyIG93biBzdG9wIHdvcmQKIyBzcGVjaWZ5IHlvdXIgc3RvcHdvcmRzIGFzIGEgY2hhcmFjdGVyIHZlY3Rvcgpkb2NzX255IDwtIHRtX21hcChkb2NzX255LCByZW1vdmVXb3JkcywgYygiYmxhYmxhMSIsICJibGFibGEyIikpIAojIFJlbW92ZSBwdW5jdHVhdGlvbnMKZG9jc19ueSA8LSB0bV9tYXAoZG9jc19ueSwgcmVtb3ZlUHVuY3R1YXRpb24pCiMgRWxpbWluYXRlIGV4dHJhIHdoaXRlIHNwYWNlcwpkb2NzX255IDwtIHRtX21hcChkb2NzX255LCBzdHJpcFdoaXRlc3BhY2UpCiMgVGV4dCBzdGVtbWluZwojIGRvY3MgPC0gdG1fbWFwKGRvY3MsIHN0ZW1Eb2N1bWVudCkKZHRtX255IDwtIFRlcm1Eb2N1bWVudE1hdHJpeChkb2NzX255KQptX255IDwtIGFzLm1hdHJpeChkdG1fbnkpCnZfbnkgPC0gc29ydChyb3dTdW1zKG1fbnkpLGRlY3JlYXNpbmc9VFJVRSkKZF9ueSA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh2X255KSxmcmVxPXZfbnkpCmhlYWQoZF9ueSwgMTApCgojTEEgd29yZCBjb3VudHMKaDJfbGEgPC1zdWJzZXQobGlzdDAzMTdfbGEsIHNlbGVjdD1jKCJzdW1tYXJ5IiwiZGVzY3JpcHRpb24iLCJuZWlnaGJvcmhvb2Rfb3ZlcnZpZXciLCJub3RlcyIsInRyYW5zaXQiLCJwcmljZSIsImFjY2VzcyIsImludGVyYWN0aW9uIikpCgpoMl9sYV9tZXJnZTwtIGRvLmNhbGwocGFzdGUwLCBsaXN0MDMxN19sYVtjKCJzdW1tYXJ5IiwiZGVzY3JpcHRpb24iLCJuZWlnaGJvcmhvb2Rfb3ZlcnZpZXciLCJub3RlcyIsInRyYW5zaXQiLCJwcmljZSIsImFjY2VzcyIsImludGVyYWN0aW9uIildKQoKaDJfbGFfdW5pb249aDJfbGFfbWVyZ2Vbc2FtcGxlKGxlbmd0aChoMl9sYV9tZXJnZSksNjAwMCldCgpkb2NzX2xhIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoaDJfbGFfdW5pb24pKQp0b1NwYWNlIDwtIGNvbnRlbnRfdHJhbnNmb3JtZXIoZnVuY3Rpb24gKHggLCBwYXR0ZXJuICkgZ3N1YihwYXR0ZXJuLCAiICIsIHgpKQpkb2NzX2xhIDwtIHRtX21hcChkb2NzX2xhLCB0b1NwYWNlLCAiLyIpCmRvY3NfbGEgPC0gdG1fbWFwKGRvY3NfbGEsIHRvU3BhY2UsICJAIikKZG9jc19sYSA8LSB0bV9tYXAoZG9jc19sYSwgdG9TcGFjZSwgIlxcfCIpCmRvY3NfbGEgPC0gdG1fbWFwKGRvY3NfbGEsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpCiMgUmVtb3ZlIG51bWJlcnMKZG9jc19sYSA8LSB0bV9tYXAoZG9jc19sYSwgcmVtb3ZlTnVtYmVycykKIyBSZW1vdmUgZW5nbGlzaCBjb21tb24gc3RvcHdvcmRzCmRvY3NfbGEgPC0gdG1fbWFwKGRvY3NfbGEsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuZ2xpc2giKSkKIyBSZW1vdmUgeW91ciBvd24gc3RvcCB3b3JkCiMgc3BlY2lmeSB5b3VyIHN0b3B3b3JkcyBhcyBhIGNoYXJhY3RlciB2ZWN0b3IKZG9jc19sYSA8LSB0bV9tYXAoZG9jc19sYSwgcmVtb3ZlV29yZHMsIGMoImJsYWJsYTEiLCAiYmxhYmxhMiIpKSAKIyBSZW1vdmUgcHVuY3R1YXRpb25zCmRvY3NfbGEgPC0gdG1fbWFwKGRvY3NfbGEsIHJlbW92ZVB1bmN0dWF0aW9uKQojIEVsaW1pbmF0ZSBleHRyYSB3aGl0ZSBzcGFjZXMKZG9jc19sYSA8LSB0bV9tYXAoZG9jc19sYSwgc3RyaXBXaGl0ZXNwYWNlKQojIFRleHQgc3RlbW1pbmcKIyBkb2NzIDwtIHRtX21hcChkb2NzLCBzdGVtRG9jdW1lbnQpCmR0bV9sYSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoZG9jc19sYSkKbV9sYSA8LSBhcy5tYXRyaXgoZHRtX2xhKQp2X2xhIDwtIHNvcnQocm93U3VtcyhtX2xhKSxkZWNyZWFzaW5nPVRSVUUpCmRfbGEgPC0gZGF0YS5mcmFtZSh3b3JkID0gbmFtZXModl9sYSksZnJlcT12X2xhKQpoZWFkKGRfbGEsIDEwKQoKc2V0LnNlZWQoMTIzNCkKcGFyKG1mcm93PWMoMSwyKSkKdzEgPC0gd29yZGNsb3VkKHdvcmRzID0gZF9ueSR3b3JkLCBmcmVxID0gZF9ueSRmcmVxLCBtaW4uZnJlcSA9IDEsCiAgICAgICAgICBtYXgud29yZHM9MjAwLCByYW5kb20ub3JkZXI9RkFMU0UsIHJvdC5wZXI9MC4zNSwgCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSkgI05ZQwp3MiA8LSB3b3JkY2xvdWQod29yZHMgPSBkX2xhJHdvcmQsIGZyZXEgPSBkX2xhJGZyZXEsIG1pbi5mcmVxID0gMSwKICAgICAgICAgIG1heC53b3Jkcz0yMDAsIHJhbmRvbS5vcmRlcj1GQUxTRSwgcm90LnBlcj0wLjM1LCAKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDgsICJEYXJrMiIpKSAjTEEKYGBgClRoaXMgaXMgYW4gaW50ZXJlc3RpbmcgdmlzdWFsaXphaXRvbiB3aGVuIHlvdSB3YW50IHRvIGtub3cgd2hhdCB0aGUgdGV4dCBjb250ZW50IG9mIGxpc3RpbmdzIHdpbGwgYmUgYWJvdXQgaW4gQWlyYm5iLiBJdCByZWZsZWN0cyB3aGF0IG1pZ2h0IGJlIGF0dHJhY3RpdmUgdG8gdHJhdmFsbGVycywgd2hhdCByZXNwZWN0cyBhcmUgY29uc2lkZXJlZCBpbXBvcnRhbnQgd2hlbiByZW50aW5nIGEgcGxhY2UuIEhvd2V2ZXIsIGR1ZSB0byB0aGUgbGltaXRlZCBjYXBhYmlsaXR5IG9mIGxvY2FsIG1hY2hpbmUsIHdlIGhhdmUgdG8gc2VsZWN0IDYwMDAgc2FtcGxlcyBmcm9tIE5ldyBZb3JrIENpdHkgYW5kIExvcyBBbmdlbGVzIHJlc3BlY3RpdmVseS4gCgpXZSBjb3VudCB0aGUgYXBwZWFyYW5jZSBmb3IgZWFjaCB3b3JkIGluIHRoZSBmb2xsb3dpbmcgdmFyaWJhbGVzOiBzdW1tYXJ5LCBkZXNjcmlwdGlvbiwgbmVpZ2hib3Job29kX292ZXJ2aWV3LCBub3RlcywgdHJhbnNpdCwgcHJpY2UsIGFjY2VzcywgaW50ZXJhY3Rpb24uIFRoZXNlIGFyZSBhbGwgdGV4dCBjb250ZW50IHZhcmlhYmxlcy4gQW5kIHRoZSBtb3JlIGNvdW50cyBhIHdvcmQgZ2V0cywgdGhlIGxhcmdlciBpdCBzaG93cyBpbiB2aXN1YWxpemFpdG9uLiAgCgpUaGUgcmVzdWx0IGlzIHZlcnkgY2xlYXIuIFdoZW4geW91IHB1dCB0aGVtIHRvZ2V0aGVyLCB5b3UgY2FuIHRlbGwgd2hpY2ggaXMgTllDL0xBIHdpdGggb25seSBvbmUgZ2xhbmNlLiBUaGUgaHVnZSAnaG9sbHl3b29kJywgJ2JlYWNoJyBhcmUgaWRlbnRpZnlpbmcgaXRzZWxmIGFzIExvcyBBbmdlbGVzLiBBbmQgYWxzbyB5b3UgY2FuIHNlZSAnTWFuaGF0dGFuJyBpbiBOWUMgdmlzdWFsaXphdGlvbiBUaGVzZSB0d28gY2l0aWVzIGFyZSB2ZXJ5IGRpc3RpbmN0aXZlIGluIHRoZSB3b3JkIGNvdW50IHZpc3VhbGl6YXRpb24uICAgCgpXaGF0J3MgbW9yZSB0byBiZSBub3RpY2VkPyBMb3MgQW5nZWxlcyBvbmUgaGFzICdob3VzZScgYW5kIE5ldyBZb3JrIG9uZSBoYXMgbm90LiBBbmQgeW91IGNhbiBpbWFnaW5lIHRoYXQgdGhlIG51bWJlciBvZiBob3VzZXMgaW4gTG9zIEFuZ2VsZXMgbWF5IGJlIG1vcmUgdGhhbiB0aGF0IG9mIE5ldyBZb3JrIENpdHkuICdLaXRjaGVuJyBzaG93cyBpbiBib3RoIHZpc3VhbGl6YXRpb25zIGFuZCBub3QgYSBzbWFsbCBvbmUuIEl0IGlzIHN1cnByaXNpbmcgdGhhdCBwZW9wbGUgY2FyZSBhYm91dCBraXRjaGVuIHRoYXQgbXVjaC4gVXN1YWxseSBpdCBpcyBhc3N1bWVkIHRoYXQgcGVvcGxlIHdpbGwgYXZvaWQgY29va2luZyB3aGVuIHRoZXkgdHJhdmVsLiBCdXQgaXQgc2VlbXMgbm90IHRoZSB0cnV0aC4gICAKCgojI01haW4gQW5hbHlzaXMKCiMjI1JlbnRhbCBMaXN0aW5nIERpc3RyaWJ1dGlvbiBBbmFseXNpcyAgCkluIHRoZSBmaXJzdCBzdGVvIHRvIGV4cGxvcmUgQWlyYm5iIGRhdGFzZXQgZGVlcGx5LCB3ZSB3b3VsZCBsaWtlIHRvIGxvb2sgYXQgaG93IHJlbnRhbCBsaXN0aW5nIGRpc3RyaWJ1dGVkIGluIGJvdGggTmV3IFlvcmsgQ2l0eSBhbmQgTG9zIEFuZ2VsZXMuCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KI0FpcmJuYiBSb29tIFR5cGUgRGlzdHJpYnV0aW9uIGluIE5ldyBZb3JrIENpdHkKcW1wbG90KGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGRhdGEgPSBsaXN0MDMxN19ueSwgbWFwdHlwZSA9ICJ0b25lci1iYWNrZ3JvdW5kIiwKICAgICAgIGRhcmtlbiA9IDAuNyxjb2xvciA9IHJvb21fdHlwZSxhbHBoYSA9SSgwLjQpLHNpemUgPSBJKDAuMSkpICsKICAgICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTIpKSkgKwogICAgICAgZ2d0aXRsZSgiQWlyYm5iIFJvb20gVHlwZSBEaXN0cmlidXRpb24gaW4gTmV3IFlvcmsgQ2l0eSAiKSArCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogICAgICAgZmFjZXRfd3JhcCh+IHJvb21fdHlwZSkKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CgojQWlyYm5iIFJvb20gVHlwZSBEaXN0cmlidXRpb24gaW4gTG9zIEFuZ2VsZXMKcW1wbG90KGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGRhdGEgPSBsaXN0MDMxN19sYSwgbWFwdHlwZSA9ICJ0b25lci1iYWNrZ3JvdW5kIiwKICAgICAgIGRhcmtlbiA9IDAuNywgY29sb3IgPSByb29tX3R5cGUsYWxwaGEgPUkoMC40KSxzaXplID0gSSgwLjEpKSArCiAgICAgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0yKSkpICsKICAgICAgIGdndGl0bGUoIkFpcmJuYiBSb29tIFR5cGUgRGlzdHJpYnV0aW9uIGluIExvcyBBbmdlbGVzIikgKwogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICAgICAgIGZhY2V0X3dyYXAofiByb29tX3R5cGUpCgpgYGAKQXMgd2UgY2FuIGNsZWFybHkgc2VlIGluIHRoZSBwbG90LHRoZXJlIGFyZSBhIGxvdCBvZiBlbnRpcmUgaG9tZS9hcHQgYW5kIHByaXZhdGUgcm9vbSBsb2NhdGUgaW4gTWFuaGF0dGFuLERvd250b3duIEJyb29rbHluLGFuZCBRdWVlbnMuQWxzbyxpdCBwcm92aWRlcyBhIGxvdCBvZiBwcml2YXRlIHJvb20gaW4gRmx1c2hpbmcsUXVlZW5zIGFuZCBTdGF0ZW4gSXNsYW5kLkl0IHNob3dzIHRoYXQgdGhlcmUgaGF2ZSBzb21lIGVudGlyZSBob21lL2FwdCBhbmQgcHJpdmF0ZSByb29tIGluIFN0YXRlbiBJc2xhbmQgYW5kIEJyb254LHdoaWxlIHRoZXJlIGFyZSBmZXcgbnVtYmVycyBvZiBzaGFyZWQgcm9vbSBsb2NhdGUgaW4gdGhlc2UgYXJlYXMsbW9zdCBvZiB0aGVtIGxvY2F0ZSBpbiBNYW5oYXR0YW4gYW5kIERvd250b3duIEJyb29rbHluLgoKTGV0J3Mgc2VlIGhvdyBMb3MgQW5nZWxlcyBkYXRhIGxvb2tzIGxpa2UuQSBsYXJnZSBhbW91bnQgb2YgZW50aXJlIGhvbWUvYXB0IGFuZCBwcml2YXRlIHJvb20gbG9jYXRlIG5lYXJieSB0aGUgYmVhY2gsc3VjaCBhcyBTYW50YSBNb25pY2EgYW5kIExvbmcgQmVhY2guTG9zIEFuZ2VsZXMgcGVvcGxlIGxvdmVzIHN1bnNoaW5lIGFuZCBiZWFjaCEgQWxzbyx0aGVyZSBhcmUgYSBsb3Qgb2YgZW50aXJlIGhvbWUvYXB0IGFuZCBwcml2YXRlIHJvb20gaW4gRFRMQSxQYXNhZGVuYSBhbmQgR2xlbmRvcmEgYXJlYS5XaGlsZSBtb3N0IG9mIHNoYXJlZCByb29tIGxvY2F0ZWQgaW4gRFRMQSBhbmQgU2FudGEgTW9uaWNhLkF0IHRoZSBsZWZ0IHNpZGUgY29ybmVyLGl0J3MgY2FsbGVkIFNhbnRhIENhdGFsaW5hIElzbGFuZC5JdCBwcm92aWRlIGEgbG90IG9mIGVudGlyZSBob21lL2FwdCBhbmQgcHJpdmF0ZSByb29tIGluIHRoaXMgc21hbGwgaXNsYW5kLgoKIyMjUHJpY2UgQ29tcGFyaXNvbiBiZXR3ZWVuIE5ldyBZb3JrIENpdHkgYW5kIExvcyBBbmdlbGVzCgpXZSBjb25zaWRlciB0aGF0IG1vc3QgdHJhdmVsZXJzIGNvbmNlcm4gcHJpY2UgaWYgaXQgaXMgZXhwZW5zaXZlIG9yIGNoZWFwLlNvIHdlIGNvbmR1Y3RlZCB0aGUgaGlzdG9ncmFtIGZvciBwcmljZSB2YXJpYWJsZS5BcyBpdCBzaG93cyBpbiB0aGUgcGxvdCxhIGxhcmdlIGFtb3VudCBvZiByZW50YWwgbGlzdGluZyBwcmljZSByYW5nZXMgZnJvbSAxMCB0byAzNTAuVGhlIGRpc3RyaWJ1dGlvbiBvZiBwcmljZSBsb29rcyBsaWtlIHJpZ2h0IHNrZXdlZC5UaGVyZSBhcmUgYSBsb3Qgb2Ygb3V0bGllcnMgdGhhdCBwcmljZSBvdmVyIDUwMCBVU0QuU28gd2UgYnVpbHQgYSBkZW5zaXR5IHBsb3Qgd2hpY2ggY29tcGFyZWQgd2l0aCB0d28gY2l0aWVzIE5ldyBZb3JrIENpdHkgYW5kIExvcyBBbmdlbGVzLkJhc2VkIG9uIGRlbnNpdHkgcGxvdCx0aGUgcGVhayB2YWx1ZSBmb3Igc2hhcmVkIHJvb20gcHJpY2UgcmFuZ2VzIGZyb20gMTAgdG8gNTAuV2hpbGUgdGhlIHBlYWsgdmFsdWUgZm9yIHByaXZhdGUgcm9vbSBwcmljZSByYW5nZXMgZnJvbSA1MCB0byAxMDAuQW5kIHRoZSBwZWFrIHZhbHVlIGZvciBlbnRpcmUgcm9vbSBwcmljZSByYW5nZXMgZnJvbSAxMDAgdG8gMjAwLkl0IHByb3ZpZGVzIHlvdSBhbiBvcHRpb24gdG8gY2hvb3NlIGEgc3VpdGFibGUgcm9vbSB0eXBlIHRoYXQgeW91IHdvdWxkIGxpa2UgdG8gc3RheS5BbGwgcGVhayB2YWx1ZSBtb3ZlcyByaWdodCBpbiBOZXcgWW9yayBDaXR5IHdoaWNoIGNvbXBhcmVzIHdpdGggTG9zIEFuZ2VsZXMuVGhhdCBtZWFucyB0aGUgYXZlcmFnZSBwcmljZSBpbiBOZXcgWW9yayBpcyBtdWNoIGhpZ2hlciB0aGFuIHRoYXQgaW4gTG9zIEFuZ2VsZXMuCgpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiMgUHJpY2UgY29tcGFyZSB3aXRoIE5ZQyBhbmQgTEEuCiMgU3VtbWFyaXplIExpc3RpbmcgUHJpY2UgCnN1bW1hcnkoYWlyYm5iX3RvdGFsJHByaWNlKQoKZ2dwbG90KGRhdGE9YWlyYm5iX3RvdGFsLCBhZXMoYWlyYm5iX3RvdGFsJHByaWNlKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDI4LAogICAgICAgICAgICAgICAgIGNvbCA9J2JsYWNrJywKICAgICAgICAgICAgICAgICBmaWxsPSJsaWdodGJsdWUiKSArIAogIGxhYnModGl0bGU9Ikhpc3RvZ3JhbSBmb3IgTGlzdGluZyBQcmljZSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIGxhYnMoeD0iTGlzdGluZyBQcmljZSIsIHk9IkZyZXF1ZW5jeSIpCgpnZ3Bsb3QoYWlyYm5iX3RvdGFsXzMsIGFlcyhwcmljZSwgY29sb3VyID0gcm9vbV90eXBlKSkgKwogIGdlb21fZGVuc2l0eShzaXplPTEsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgc3RhdF9kZW5zaXR5KGFlcyh4PXByaWNlLCBjb2xvdXI9cm9vbV90eXBlKSwgZ2VvbT0ibGluZSIsIHBvc2l0aW9uPSJpZGVudGl0eSIgKSAgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTIpKSkrCiAgeGxhYigiUHJpY2UiKSArCiAgZ2d0aXRsZSgiRGVuc2l0eSBEaXN0cmlidXRpb24gb2YgUHJpY2UgQnkgUm9vbSBUeXBlIikgKwogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICBmYWNldF93cmFwKCB+Y2l0eV9uYW1lICxuY29sPSAxKQoKZ2dwbG90KHN1YnNldChhaXJibmJfdG90YWxfMyxjaXR5X25hbWUgPT0iTmV3IFlvcmsgQ2l0eSIpLCBhZXMoeD1uZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkLCB5PXByaWNlLCBmaWxsPXJvb21fdHlwZSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgeGxhYigiRGlzdHJpY3QgQXJlYSIpICsKICB5bGFiKCJQcmljZSBpbiBEb2xsYXJzIChVU0QpIikgKwogIGdndGl0bGUoIlByaWNlIEJ5IFJvb20gVHlwZSBpbiBEaWZmZXJlbnQgQXJlYXMgaW4gTmV3IFlvcmsgQ2l0eSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCmBgYApTbyB3ZSB3YW50IHRvIGRlZXBseSBsb29rIGF0IHRoZSBwcmljZSBiYXNlZCBvbiB0eXBlIG9mIHJvb20gYW5kIGRpc3RyaWN0IGFyZWFzIGluIGJvdGggY2l0aWVzLiBVbmZvcnR1bmF0ZWx5LCBkaXN0cmljdCBhcmVhIHZhcmlhYmxlKG5laWdoYm91cmhvb2RfZ3JvdXBfY2xlYW5zZWQpIGlzIG5vdCBhdmFpbGFibGUgaW4gTG9zIEFuZ2VsZXMsIHNvIHdlIHdpbGwgb25seSBleHBsb3JlIGluIE5ldyBZb3JrIENpdHkgZGF0YS5BY2NvcmRuaW5nIHRvIHRoZSByZXN1bHQgb2YgYm94cGxvdCxwcmljZSBvZiBlbnRpcmUgaG9tZS9hcHQgaXMgbXVjaCBleHBlbnNpdmUgdGhhbiB0aGUgb3RoZXIgdHdvLiBQcml2YXRlIHJvb20gaXMgdGhlIHNlY29uZCBleHBlbnNpdmUgb25lLlNoYXJlZCByb29tIHByb3ZpZGVzIHRoZSBjaGVhcGVzdCBwcmljZS5BcyB3ZSBjYW4gc2VlLGFsdGhvdWdoIHdlIHJlbW92ZSBvdXRsaWVycyB0aGF0IHByaWNlIG92ZXIgNTAwIFVTRCxpdCBzdGlsbCBoYXZlIGEgbG90IG9mIG91dGxpZXJzIGluIHRoZSBib3hwbG90IGJhc2VkIG9uIGRpZmZlcmVudCByb29tIHR5cGUgYW5kIGRpZmZlcmVudCBkaXN0cmljdCBhcmVhLkl0IHNob3dzIHRoYXQgcm9vbXMgaW4gTWFuaGF0dGFuIGlzIG11Y2ggZXhwZW5zaXZlIHRoYW4gb3RoZXIgZGlzdHJpY3QuVGhlIG1lZGlhbiBwcmljZSBvZiBlbnRpcmUgcm9vbS9hcHQgaW4gTWFuaGF0dGFuIGlzIGFyb3VuZCAxODAgVVNELkFuZCB0aGUgbWVkaWFuIHByaWNlIG9mIHByaXZhdGUgcm9vbSBpbiBNYW5oYXR0YW4gaXMgbGVzcyAxMDAgVVNELGFyb3VuZCA4MCBVU0QuIFNvIGlmIHdlIHdhbnQgdG8gc2F2ZSBzb21lIG1vbmV5LHdlIHN1Z2dlc3QgdGhhdCB5b3UgY2FuIGNob29zZSBwcml2YXRlIHJvb20gaW4gTWFuaGF0dGFuIGFuZCBsb29rIGF0IG90aGVyIGRpc2NyaWN0IGFyZWEsc3VjaCBhcyBCcm9va2x5biBhbmQgUXVlZW5zLgoKIyMjI1BhcmFsbGVsIENvb3JkaW5hdGUgUGxvdCBvZiBWYXJpb3VzIFByaWNlIExldmVscwpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiMgUENQIFBsb3QgCmFibiA8LSBhaXJibmJfdG90YWxbYWlyYm5iX3RvdGFsJHByaWNlIDw9IDUwMCAsIF0KcXVhbnRpbGUoYWJuJHByaWNlLCBwcm9icyA9IGMoMCwgMC4yNSwgMC41LCAwLjc1LCAxKSwgbmEucm0gPSBUUlVFKQphYm4kc2VjdXJpdHlfZGVwb3NpdFthYm4kc2VjdXJpdHlfZGVwb3NpdD09IiJdIDwtICcwJwphYm4kY2xlYW5pbmdfZmVlW2FibiRjbGVhbmluZ19mZWU9PSIiXSA8LSAnMCcKYWJuJHNlY3VyaXR5X2RlcG9zaXQgPC0gYXMubnVtZXJpYyhhYm4kc2VjdXJpdHlfZGVwb3NpdCkKYWJuJGNsZWFuaW5nX2ZlZSA8LSBhcy5udW1lcmljKGFibiRjbGVhbmluZ19mZWUpCmFibiRzZWN1cml0eV9kZXBvc2l0W2lzLm5hKGFibiRzZWN1cml0eV9kZXBvc2l0KV0gPC0gMAphYm4kY2xlYW5pbmdfZmVlW2lzLm5hKGFibiRjbGVhbmluZ19mZWUpXSA8LSAwCgphYm4kZXh0cmFfZmVlIDwtIGFibiRzZWN1cml0eV9kZXBvc2l0ICsgYWJuJGNsZWFuaW5nX2ZlZQpwY3AgPC0gYWJuW2FibiRleHRyYV9mZWUgPiAwLCBdCnBjcCA8LXN1YnNldChwY3Asc2VsZWN0PWMoInByaWNlIiwiY2l0eV9uYW1lIiwicm9vbV90eXBlIiwiaG9zdF9yZXNwb25zZV90aW1lIiwicmV2aWV3X3Njb3Jlc19yYXRpbmciLCJleHRyYV9mZWUiKSkKI25yb3cocGNwKQpwY3AkcHJpY2VMZXZlbCA8LSAnMCAtIDI1JScKcGNwJHByaWNlTGV2ZWxbcGNwJHByaWNlPj02OV0gPC0gJzI1JSAtIDUwJScKcGNwJHByaWNlTGV2ZWxbcGNwJHByaWNlPj0xMDBdIDwtICc1MCUgLSA3NSUnCnBjcCRwcmljZUxldmVsW3BjcCRwcmljZSA+IDE2MF0gPC0gJzc1JSBhbmQgYWJvdmUnCgpwY3Bfc2FtcGxlIDwtcGNwW3NhbXBsZSgxOm5yb3cocGNwKSwgMjUwMDAsIHJlcGxhY2U9RkFMU0UpLF0KCmdncGFyY29vcmQocGNwX3NhbXBsZSwgY29sdW1ucyA9IDI6NiAsIGdyb3VwQ29sdW1uID0gJ3ByaWNlTGV2ZWwnLCBzY2FsZSA9ICd1bmltaW5tYXgnLCB0aXRsZSA9ICJQYXJhbGxlbCBDb29yZGluYXRlIFBsb3QgZm9yIFByaWNlIExldmVsIChzYW1wbGUgc2l6ZSA9IDI1MDAwKSIpICsKICBnZW9tX2xpbmUoc2l6ZT0xLjI1KSArCiAgbGFicyh5PSIiKSsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NSwgaGp1c3Q9MSksIAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKYGBgClBhcmFsbGVsIGNvb3JkaW5hdGUgcGxvdCBpcyBpZGVhbCBmb3Igc2hvd2luZyBob3cgb25lIHNpbmdsZSB2YXJpYWJsZSBpcyBjaGFuZ2luZyBpbiBjb29yZGluYXRpb24gd2l0aCBhIGEgc2VyaWVzIG9mIHZhcmliYWxlcy4gSGVyZSwgdGhlIHNpbmdsZSB2YXJpYWJsZSBpcyBwcmljZSBsZXZlbCBhbmQgdGhlIHZhcmlhYmxlcyB3ZSB3YW50IHRvIGxvb2sgYXQgYXJlIGNpdGllcywgcm9vbSB0eXBlcywgaG9zdCByZXNwb25zZSB0aW1lLCByZXZpZXcgc2NvcmUgcmF0aW5ncywgYW5kIGV4dHJhIGZlZS4gIAoKRXh0cmEgZmVlIGlzIG5vdCBhIHZhcmlhYmxlIGZyb20gb3JpZ2luYWwgZGF0YXNldC4gSXQgaXMgYSBzdW0gb2Ygc2VjdXJpdHkgZGVwb3NpdCBhbmQgY2xlYW5pbmcgZmVlIGlmIGVpdGhlciBvZiBpdCBleGlzdHMuIFdlIHdhbnQgdG8gY3JlYXRldCB0aGlzIGxhYmVsIHNpbmNlIHdlIGJlbGlldmUgdGhhdCByZW50IHByaWNlIG1pZ2h0IGJlIGNvcnJlbGF0ZWQgd2l0aCB0aGUgZXh0cmEgYW1vdW50IG9mIG1vbmV5LiBJbiByZWFsIGxpZmUsIG9uZSBjYW4gZWFzaWx5IGFzc3VtZSB0aGF0LCB0aGUgYmV0dGVyIGFuIGFjY29tbW9kYXRpb24gaXMuIHRoZSBoaWdoZXIgcHJpY2UgaXQgdGFrZXMuIFdoZW4geW91IHZpc2l0IGEgbHV4dXJ5IGhvdGVsLCB5b3UgYXJlIG1vcmUgbGlrZWx5IHRvIHBheSBoaWdoZXIgc2VjdXJpdHkgZGVwb3NpdCBhbmQgY2xlYW5pbmcgZmVlIGFmdGVyIHN0YXlpbmcuIFRoYXQgaXMgd2h5IHdlIGNyZWF0ZSB0aGlzIHZhcmlhYmxlIHRvIGNoZWNrIGlmIGl0IGlzIGNvcnJlbGF0ZWQgd2l0aCByZW50IHByaWNlLiAgCgpXaGVuIHBsb3R0aW5nIFBDUCwgdGhlIGxhcmdlIGFtb3VudCBvZiBkYXRhIGNhbm5vdCBiZSBoYW5kbGVkIGJ5IG91ciBsb2NhbCBtYWNoaW5lLiBTbyBpdCBpcyBiZXR0ZXIgdG8gdGFrZSBhIHNhbXBsZSB0byBkbyBwbG90dGluZy4gVGhlIHNpemUgMjUwMDAgaXMgbmVhcmx5IHRoZSBtYXhpbXVtIHdoaWNoIGxvY2FsIG1hY2hpbmUgaXMgY2FwYWJsZSBvZi4gT25lIHRoaW5nIG5lZWQgdG8gYmUgbm90aWNlZCBpcyB0aGF0IHdlIGV4Y2x1ZGUgc2FtcGxlcyB3aG9zZSBleHRyYSBmZWUgZXF1YWxpbmcgdG8gemVyby4gSXQgaXMgYmV0dGVyIHRvIGNoZWNrIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGV4dHJhIGZlZSBhbmQgcmVudCBwcmljZS4gQW5kIHRoZSB0b3RhbCBzaXplIG9mIGRhdGEgd2l0aCBleHRyYSBmZWUgYmVpbmcgbGFyZ2VyIHRoYW4gemVybyBpcyBtb3JlIHRoYW4gNDAwMDAuIEl0IGlzIHZlcnkgcmVhc29uYWJsZSB0byB0YWtlIGEgc2FtcGxlIGZyb20gdGhhdCBsYXJnZSBzaXplLiAgCgpMb29raW5nIGF0IHRoaXMgUENQLCB0aGUgZmlyc3QgdGhyZWUgdmFyaWFibGVzIGFyZSBkaXNjcmVhdGUgb25lcy4gV2UgY2FuIGVhc2lseSBzZWUgdGhhdCAwIC0gMjUlIGFyZSB2ZXJ5IGFjdGl2ZSBpbiB0aGVzZSB0aHJlZSB2YXJpYWJsZXMuIFNvIHdlIGtub3cgMCAtIDI1JSBoYXZlIGxhcmdlIHNwcmVhdCBpbiBjaXRpZXMsIHJvb20gdHlwZXMsIGFuZCBob3N0IHJlc3BvbnNlIHRpbWUuIEluIGxhc3QgdHdvIHZhcmlhYmxlcywgdHdvIHBvaW50cyBuZWVkIHRvIGJlIG5vdGljZWQuIE9uZSBpcyB0aGF0IHB1cnBsZSBsaW5lIGFwcGVhcnMgbW9yZSBpbiB0b3AsIHdoaWNoIG1lYW5zIGhpZ2ggcHJpY2UgY29ycmVsYXRlcyB3aXRoIGhpZ2ggcmF0aW5ncyBhbmQgbW9yZSBleHRyYSBmZWUuIFRoZXJlIHNlZW1zIHRvIGJlIHNvbWUgb3V0bGllcnMgaW4gaGlnaCBleHRyYSBmZWUuIFRoZXNlIGhpZ2ggZXh0cmEgZmVlIGFyZSBtb3JlIGxpa2VseSB0byBiZSA3NSUgYW5kIGFib3ZlIHByaWNlIGxldmVsLiBUaGUgb3RoZXIgcG9pbnQgaXMgdGhhdCBzY29yZSByYXRpbmcgaXMgdGVuZCB0byBoaWdoZXIuIEl0IG1pZ2h0IGluZGljYXRlIHRoYXQgcGVvcGxlIGxpa2UgdG8gZ2l2ZSBhIGdvb2Qgc2NvcmUgdG8gdGhlIGhvc3RzLiBNb3JlIGRldGFpbHMgb24gdGhlc2UgdmFyaWFibGVzIHdpbGwgYmUgaW4gZm9sbG93aW5nIHBhcnRzLiAKICAKIyMjQXZhaWxhYmxpdHkgQW5hbGF5c2lzCgpMZXQncyBsb29rIGF0IGBBdmFpbGFibGl0eV8zNjVgIHZhcmlhYmxlLkl0IHNob3dzIHRoZSBudW1iZXIgb2YgZGF5cyB0aGUgcmVzaWRlbmNlIGlzIGF2YWlsYWJsZSB0byByZW50ZXJzIGJ5IHRoZSBob3N0IHdpdGhpbiAzNjUgZGF5cyBzcGFuIGFmdGVyIHRoZSBsaXN0aW5nIHdhcyBwb3N0ZWQuVGhpcyBpcyBhIGZhY3RvciB0byBzZWUgd2hldGhlciB0aGVzZSByZW50YWwgbGlzdGluZyBpcyB1bmRlciBsZWF2ZSB1bnVzZWQuRmlyc3Qsd2UgZXhwbG9yZSBhIHN1bW1hcnkgdG8gc2VlIHRoaXMgdmFyaWFibGUuVGhlIG1lZGlhbiB2YWx1ZSBlcXVhbHMgdG8gMTQzIGRheXMsYW5kIG1lYW4gdmFsdWUgZXF1YWxzIHRvIDE2OC42IGRheXMuVGhhdCBtZWFucyB0aGVyZSBhcmUgYWxtb3N0IGhhbGYgYSB5ZWFyIHRoZSByZXNpZGVuY2UgaXMgdW5kZXIgbGVhdmUgdW51c2VkLlNvIHBlb3BsZSB3b3VsZCBsaWtlIHRvIHNoYXJlIHRoZWlyIHJlc2lkZW5jZSB0byBvdGhlciBwZW9wbGUgaWYgdGhleSBuZWVkLkJhc2VkIG9uIGhpc3RvZ3JhbSx0aGVyZSBhcmUgdHdvIHBlYWtzIGluIHRoZSBwbG90LkEgbGFyZ2UgYW1vdW50IG9mIHJlc2lkZW5jZSBsaXN0aW5nIGZhbGwgaW50byAxLTEwIGRheXMgYW5kIDM1NS0zNjUgZGF5cy5BbHNvLHRoZXJlIGFyZSBhIGxvdCBhdmFpbGFibGUgbGlzdGluZyByYW5nZXMgZnJvbSAxMC0xMDAgZGF5cyBhbmQgMjcwIC0zNjUgZGF5cy5TbyB3ZSB0cmFuZm9ybSBudW1lcmljYWwgdmFyaWFibGUgaW50byBjYXRlZ29yaWNhbCB2YXJpYWJsZSB3aXRoIDQgbGV2ZWxzKDEtMyBtb250aHMsNC02IG1vbnRocyw3LTkgbW9udGhzLGFuZCAxMC0xMiBtb250aHMpLgoKYGBge3Igd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQojIEF2YWlsYWJsaXR5XzM2NQphaXJibmJfdG90YWwkYXZhaWxhYmlsaXR5XzM2NSA8LSBhcy5udW1lcmljKGFpcmJuYl90b3RhbCRhdmFpbGFiaWxpdHlfMzY1KQpzdW1tYXJ5KGFpcmJuYl90b3RhbCRhdmFpbGFiaWxpdHlfMzY1KQoKZ2dwbG90KGRhdGE9YWlyYm5iX3RvdGFsLCBhZXMoYWlyYm5iX3RvdGFsJGF2YWlsYWJpbGl0eV8zNjUpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMTAsCiAgICAgICAgICAgICAgICAgY29sID0nYmxhY2snLAogICAgICAgICAgICAgICAgIGZpbGw9ImxpZ2h0Ymx1ZSIpICsgCiAgbGFicyh0aXRsZT0iSGlzdG9ncmFtIGZvciBBdmFpbGFiaWxpdHkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICBsYWJzKHg9IkF2YWlsYWJsZSBEYXlzIiwgeT0iRnJlcXVlbmN5IikKCiMgY3JlYXRlIEF2YWlsYWJsZV9RdWFydGVyIGJhc2VkIG9uIEF2YWlsYWJsaXR5XzM2NQoKYWlyYm5iX3RvdGFsJGF2YWlsYWJsZV9xdWFydGVyW2FpcmJuYl90b3RhbCRhdmFpbGFiaWxpdHlfMzY1IDw9OTEgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhaXJibmJfdG90YWwkYXZhaWxhYmlsaXR5XzM2NSA+PTBdIDwtICIxLTMgTW9udGhzIgphaXJibmJfdG90YWwkYXZhaWxhYmxlX3F1YXJ0ZXJbYWlyYm5iX3RvdGFsJGF2YWlsYWJpbGl0eV8zNjUgPD0xODEgJiAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWlyYm5iX3RvdGFsJGF2YWlsYWJpbGl0eV8zNjUgPjkxXSA8LSAnNC02IE1vbnRocycKYWlyYm5iX3RvdGFsJGF2YWlsYWJsZV9xdWFydGVyW2FpcmJuYl90b3RhbCRhdmFpbGFiaWxpdHlfMzY1IDw9MjcxICYgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWlyYm5iX3RvdGFsJGF2YWlsYWJpbGl0eV8zNjUgPjE4MV0gPC0gJzctOSBNb250aHMnCmFpcmJuYl90b3RhbCRhdmFpbGFibGVfcXVhcnRlclthaXJibmJfdG90YWwkYXZhaWxhYmlsaXR5XzM2NSA8PSAzNjUmICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhaXJibmJfdG90YWwkYXZhaWxhYmlsaXR5XzM2NSA+MjcxXSA8LSAnMTAtMTIgTW9udGhzJwphaXJibmJfdG90YWwkYXZhaWxhYmxlX3F1YXJ0ZXIgPC0gZmFjdG9yKGFpcmJuYl90b3RhbCRhdmFpbGFibGVfcXVhcnRlcikKCmFpcmJuYl90b3RhbCRhdmFpbGFibGVfcXVhcnRlciA8LSBmYWN0b3IoYWlyYm5iX3RvdGFsJGF2YWlsYWJsZV9xdWFydGVyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjEtMyBNb250aHMiLCAiNC02IE1vbnRocyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNy05IE1vbnRocyIsICIxMC0xMiBNb250aHMiKSkKCnN1bW1hcnkoYWlyYm5iX3RvdGFsJGF2YWlsYWJsZV9xdWFydGVyKQoKZ2dwbG90KGFpcmJuYl90b3RhbCwgYWVzKGF2YWlsYWJpbGl0eV8zNjUsIGNvbG91ciA9IHJvb21fdHlwZSkpICsKICBnZW9tX2RlbnNpdHkoc2l6ZSA9MSAsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICB4bGFiKCJBdmFpbGFibGUgRGF5cyIpICsKICBnZ3RpdGxlKCJEZW5zaXR5IERpc3RyaWJ1dGlvbiBvZiBBdmFpbGFiaWxpdHkgIikgKwogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgCiAgc3RhdF9kZW5zaXR5KGFlcyh4PWF2YWlsYWJpbGl0eV8zNjUsIGNvbG91cj1yb29tX3R5cGUpLCBnZW9tPSJsaW5lIiwgcG9zaXRpb249ImlkZW50aXR5IiApICArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MikpKQpgYGAKVGhlIGhpc3RvZ3JhbSBtYWtlcyBhbiBpbnRlcmVzdGluZyBkaXN0cmlidXRpb24gaW4gYXZhaWxhYmxlIGRheXMuIEJvdGggdGhlIGJhcnMgYXQgdGhlIGJlZ2lubmluZyBhbmQgdGhlIGVuZCBoYXZlIGV4dHJlbWVseSBoaWdoIGNvdW50cywgd2hpY2ggbWVhbnMgdGhhdCB0aGVyZSBhcmUgYSBsYXJnZSBwZXJjZW50YWdlIG9mIGhvc3RzIGFyZSBlaXRoZXIgYXZhaWxhYmxlIGZvciBvbmx5IGEgZmV3IGRheXMgaW4gYSB5ZWFyIG9yIGF2YWlsYWJsZSBhbG1vc3QgZm9yIGEgd2hvbGUgeWVhci4gVGhlbiB3ZSBoYXZlIGFuIGFzc3VtcHRpb24gdGhhdCB0aGUgaG9zdHMgYXJlIG5vdCB1cGRhdGluZyB0aGVpciBhdmFpbGFiaWxpdHkgb24gdGhlIHdlYnNpdGUgc28gdGhleSBhcmUgcmVjb3JkZWQgYXMgYXZhaWxhYmxlIGZvciAzNjUgZGF5cy4gVGhlbiB3ZSB0cnkgdG8gZWxpbWluYXRlIHRoZSB2YWx1ZSBvZiAzNjUgYW5kIHBsb3QgYWdhaW4uIEJ1dCB0aGUgdHJlbmQgc3RpbGwga2VlcHMuIFRodXMgd2UgdGhpbmsgdGhlIG9yaWdpbmFsIGRhdGEgbWF5IGluZGljYXRlIHRoYXQgcXVpdGUgYSBwZXJjZW50YWdlIG9mIGhvc3RzIGFyZSBkb2luZyBBaXJibmIgZm9yIGEgY2FzdWFsIGRheXMgYW5kIGRvIG5vdCBkZXBlbmQgb24gdGhlIHJlbnQgbW9uZXkgd2hpbGUgYW5vdGhlciBsYXJnZSBwcm9wb3J0aW9uIG9mIHBlb3BsZSBhcmUgZGVwZW5kaW5nIG9uIGl0LiAgCgpUaGUgZGVuc2l0eSBzaG93cyBob3cgYXZhaWxhYmxlIGRheXMgZGlzdHJpYnV0ZXMgaW4gcm9vbSB0eXBlcy4gV2UgY2FuIHNlZSB0aGF0IHNoYXJlZCByb29tIHR5cGUgZG9lcyBub3Qga2VlcCB0aGUgdHJlbmQgYXQgdGhlIGJlZ2lubmluZyBiYXIuIEl0IGFwcGVhcnMgdGhhdCBzaGFyZWQgcm9vbXMgYXJlIGhhdmluZyBtb3JlIGF2YWlsYWJpbGl0eSBjb21wYXJlZCB0byBvdGhlcnMuIE5vdyB3ZSBtaWdodCBpbWFnaW5lIHRoYXQgc2hhcmVkIHJvb21zIGFyZSBtb3JlIGZsZXhpYmxlIHRoYW4gZW50aXJlIG9uZXMgc28gaXQgd2lsbCBoYXZlIG1vcmUgYXZhaWxhYmlsaXR5LiBJdCBpcyBmdXJ0aGVyIHZhbGlkYXRlZCBieSB0aGUgZmFjdCB0aGF0IGVudGlyZSBob21lL2FwdCBpcyBnb2luZyBsb3cgYXQgdGhlIGVuZCBvZiBkZW5zaXR5LCB3aGljaCBtZWFucyB0aGVyZSBpcyBsZXNzIHBlb3BsZSBhcmUgcmVudGluZyBlbnRpcmUgaG9tZS9hcHQgZm9yIGEgbG9uZyBwZXJpb2QgY29tcGFyZWQgdG8gb3RoZXIgcm9vbSB0eXBlcy4KCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KI05ZQyAKZyA8LSBnZ3Bsb3Qoc3Vic2V0KGFpcmJuYl90b3RhbCxuZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkICE9Ik5BIiksIGFlcyhhdmFpbGFibGVfcXVhcnRlciwgZmlsbD1uZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpICsKICB4bGFiKCJBdmFpbGFibGUgRGF5cyIpICsKICBnZ3RpdGxlKCJBdmFpbGFibGUgU3RheXMgaW4gRGlmZmVyZW5jZSBab25lcyhOZXcgWW9yaykgYnkgUm9vbSBUeXBlIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICNheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9MzAsaGp1c3QgPSAxKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkrCiAgZmFjZXRfd3JhcCggfnJvb21fdHlwZSkKZ2dwbG90bHkoZykKYGBgCgpFbnRpcmUgcm9vbS9hcHQgaGFzIGxhcmdlIG51bWJlcnMgb2YgYXZhaWxhYmxlIHJlc2lkZW5jZSBpbiAxLTMgbW9udGhzLCB0aGUgMm5kIGxhcmdlc3QgbnVtYmVyIG9mIGF2YWlsYWJsZSByZXNpZGVuY2UgaXMgaW4gMTAtMTIgbW9udGhzLCB0aGVuIDQtNiBtb250aHMgYW5kIDctOSBtb250aHMuSXQgZGlkbid0IHNob3cgbXVjaCBhdmFpbGFibGUgcmVzaWRlbmNlIGZvciBzaGFyZWQgcm9vbSBpbiA0LTYgbW9udHMgYW5kIDctOSBtb250aHMuCgpXaXRoaW4gRW50aXJlIFJvb20vQXB0IHR5cGUsTWFuaGF0dGFuIGFyZWEgcHJvdmlkZXMgdGhlIGxhcmdlc3QgYXZhaWxhYmxlIGxpc3RpbmdzIHRocm91Z2ggYSB3aG9sZSB5ZWFyLlRoZSBzZWNvbmQgbGFyZ2VzdCBhdmFpbGFibGUgbGlzdGluZ3MgaXMgaW4gQnJvb2tseW4sZXNwZWNpYWxseSBpZiB5b3Ugd2FudCB0byBzdGF5IHdpdGhpbiAxLTMgbW9udGhzIHNob3J0IHRlcm0gb3IgMTAtMTIgbW9udGhzIGxvbmcgdGVybS5JbiBwcml2YXRlIHJvb20gcmVzaWRlbmNlLEJyb29rbHluIGFyZWEgcHJvdmlkZXMgdGhlIGxhcmdlc3QgYXZhaWxhYmxlIHJlc2lkZW5jZSBpbiAxLTMgbW9udGhzIGFuZCAxMC0xMiBtb250aHMuU28gaWYgeW91IGNvbnNpZGVyIHRoYXQgRW50aXJlIFJvb20vQXB0IGNvc3QgeW91IHRvbyBtdWNoLGNob29zaW5nIHByaXZhdGUgcm9vbSBpbiBCcm9va2x5biBpcyBhIGdvb2QgY2hvaWNlLkJ1dCBpZiB5b3UgdGhpbmsgMS0zIG1vbnRocyBpcyB0b28gc2hvcnQgYW5kIDEwIC0xMiBtb250aHMgaXMgdG9vIGxvbmcseW91IGNhbiBhbHNvIGZpbmQgYSBnb29kIHBsYWNlIGluIE1hbmhhdHRhbiBhbmQgQnJvb2tseW4uTWFuaGF0dGFuIHByb3ZpZGVzIG92ZXIgdGhvdXNhbmQgYXZhaWxhYmxlIEVudGlyZSBSb29tL0FwdCByZXNpZGVuY2UgaW4gNC02IG1vbnRocyBvcHRpb24uQWxzbyxCcm9va2x5biBwcm92aWRlcyBsZXNzIHRob3VzYW5kLGFyb3VuZCA4MDAgbGlzdGluZ3MgaW4gNC0gNiBtb250aHMuCgojIyNNaW5pbXVuIE5pZ2h0cyBSZXF1aXJlbWVudCBBbmFseXNpcwpXZSBhbHNvIHdvdWxkIGxpa2UgdG8gY2hlY2sgdGhhdCB3aGV0aGVyIHRob3NlIGF2YWlsYWJsZSByZXNpZGVuY2UgaGF2ZSBtaW5pbXVtIHN0YXlzIHJlcXVpcmVtZW50LiBXZSBjaG9vc2UgbWluaW11bSBuaWdodHMgdmFyaWFibGUgdG8gZXhwbG9yZS4gQmFzZWQgb24gc3VtbWFyeSByZXBvcnQsYWxsIHJlbnRhbCBsaXN0aW5ncyByZXF1aXJlIG1pbmltdW0gMSBuaWdodCBzdGF5LlRoZSBtZWRpYW4gdmFsdWUgZXF1YWxzIHRvIDIsYW5kIG1lYW4gdmFsdWUgZXF1YWxzIHRvIDMuNyBuaWdodHMuVGhhdCBtZWFucyB0aGUgYXZlcmFnZSBtaW5pbXVtICByZXF1aXJlcyA0IG5pZ2h0cyB0byBzdGF5LlRoZW4gd2UgbWFrZSBhIG5ldyBjYXRlZ29yaWNhbCB2YXJpYWJsZSB0byB0cmFuc2Zvcm0gbnVtZXJpY2FsIG9uZS5JbiBuZXcgdmFyaWFibGUsdGhlcmUgYXJlIDUgbGV2ZWxzKDEgbmlnaHRzLDItMyBuaWdodHMsNC01IG5pZ2h0cyw2LTcgbmlnaHRzLGFuZCA3IG1vcmUgbmlnaHRzKS4KCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KI21pbmltdW4gbmlnaHRzIHJlcXVpcmVtZW50CnN1bW1hcnkoYWlyYm5iX3RvdGFsJG1pbmltdW1fbmlnaHRzKQoKYWlyYm5iX3RvdGFsJGNhdF9uaWdodFthaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPT0xXSA8LSAiMSBOaWdodCIKYWlyYm5iX3RvdGFsJGNhdF9uaWdodFthaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPjEgJiBhaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPD0zXSA8LSAiMi0zIE5pZ2h0cyIKYWlyYm5iX3RvdGFsJGNhdF9uaWdodFthaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPjMgJiBhaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPD01XSA8LSAiNC01IE5pZ2h0cyIKYWlyYm5iX3RvdGFsJGNhdF9uaWdodFthaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPjUgJiBhaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPD03XSA8LSAiNi03IE5pZ2h0cyIKYWlyYm5iX3RvdGFsJGNhdF9uaWdodFthaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPjcgJiBhaXJibmJfdG90YWwkbWluaW11bV9uaWdodHMgPD0zMF0gPC0gIjcgTmlnaHRzIE1vcmUiCgphaXJibmJfdG90YWwkcHJpY2UgPC0gYXMubnVtZXJpYyhnc3ViKCJcXCQiLCAiIiwgYWlyYm5iX3RvdGFsJHByaWNlKSkgI3JlbW92ZSAkIHNpZ24KCnRhYmxlKGFpcmJuYl90b3RhbCRjYXRfbmlnaHQsYWlyYm5iX3RvdGFsJHJvb21fdHlwZSkKdGFibGUoYWlyYm5iX3RvdGFsJGNhdF9uaWdodCkKCmdncGxvdChzdWJzZXQoYWlyYm5iX3RvdGFsLGNhdF9uaWdodCAhPSJOQSIpLCBhZXMoY2F0X25pZ2h0LCBmaWxsID1yb29tX3R5cGUpKSArIAogIGdlb21fYmFyKCkgKwogIHhsYWIoIk1pbmltdW0gTmlnaHRzKERheXMpIikgKwogIGdndGl0bGUoIk1pbmltdW0gTmlnaHRzIGJ5IFJvb20gVHlwZSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIGZhY2V0X3dyYXAofiBjaXR5X25hbWUpICsKICBjb29yZF9mbGlwKCkKCmcgPC1nZ3Bsb3Qoc3Vic2V0KGFpcmJuYl90b3RhbCxwcmljZSA8PTUwMCAgJiBjYXRfbmlnaHQgIT0iTkEiKSwgYWVzKHByaWNlLCBjb2xvdXIgPSBjYXRfbmlnaHQpKSArCiAgZ2VvbV9kZW5zaXR5KHNpemUgPSAxLCBzaG93X2d1aWRlID0gRkFMU0UpICsKICB4bGFiKCJQcmljZSIpICsKICBnZ3RpdGxlKCJEZW5zaXR5IERpc3RyaWJ1dGlvbiBvZiBQcmljZSBCeSBNaW5pbXVtIE5pZ2h0cyIpICsKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSsgCiAgc3RhdF9kZW5zaXR5KGFlcyh4PXByaWNlLCBjb2xvdXI9Y2F0X25pZ2h0KSwgZ2VvbT0ibGluZSIsIHBvc2l0aW9uPSJpZGVudGl0eSIgKSAgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTIpKSkKZ2dwbG90bHkoZykKYGBgCkluIE5ldyBZb3JrIENpdHksdGhlIGxhcmdlc3QgbnVtYmVyIG9mIG1pbmltdW0gc3RheXMgaXMgMi0zIG5pZ2h0cyBpbiBOZXcgWW9yayBDaXR5LCB3aGlsZSB0aGUgbGFyZ2VzdCBudW1iZXIgb2YgbWluaW11bSBzdGF5cyBpcyAxIG5pZ2h0cyBpbiBMb3MgQW5nZWxlcy5TbyBOZXcgWW9yayBDaXR5IG1heSBoYXZlIG1vcmUgc3RyaWN0IGJvb2tpbmcgcG9saWN5IHRoYW4gdGhhdCBpbiBMb3MgQW5nZWxlcy5XZSB3aWxsIGV4cGxvcmUgdGhpcyBwcm9ibGVtIG9uIGZ1cnRoZXIgZGlzY3Vzc2lvbnMuSXQgc2VlbXMgdGhhdCBhIGxhcmdlIG51bWJlciBvZiBsaXN0aW5ncyBpbiBwcml2YXRlIHJvb20gaGFzIDEgbmlnaHRzIG1pbmltdW0gd2l0aGluIGJvdGggY2l0aWVzLHdoaWxlIGVudGlyZSBob21lL2FwdCBoYXMgbGFyZ2VyIG51bWJlciBvZiBsaXN0aW5ncyBpbiBib3RoIGNpdGllcyBmb3IgMi0zIG5pZ2h0cyBtaW5pbXVtLgoKQmFzZWQgb24gZGVzaXR5IHBsb3QscHJpY2UgcmFuZ2VzIGZyb20gMTAgdG8gMTAwIFVTRCxpdCBwcm92aWRlcyBtb3JlIGZyaWVuZGx5IG1pbmltdW0gbmlnaHRzIHJlcXVpcmVtZW50IGZvciBvbmx5IDEgbmlnaHQuUHJpY2UgcmFuZ2VzIGZyb20gMTAwIHRvIDMwMCBVU0QsbW9zdCByZW50YWwgbGlzdGluZ3MgcmVxdWlyZSAyLTMgbmlnaHRzIG1pbmltdW0uV2hpbGUgcHJpY2Ugb3ZlciAzMDAgVVNELGEgbG90IG9mIGxpc3RpbmdzIHJlcXVpcmUgNC01IG5pZ2h0cyBvciBtb3JlIG1pbmltdW0gc3RheXMuCgojIyNUb3AgSG9zdCBMaXN0aW5ncyBBbmFseXNpcwpJbiBvcmRlciB0byByZXByZXNlbnQsIGNvbXBhcmUgYW5kIGFuYWx5bGl6ZSB0aGUgdG9wIGhvc3RzIGluIE5ZQyBhbmQvdi5zLiBMQSwgd2UgY2hvb3NlIHRvIHVzZSBUaGUgY2VsZXZsYW5kIGRvdCBwbG90IHRvIHNob3cgdGhlIHRvdGFsIGhvc3QgbnVtYmVycyBpbiBhIGRlc2NlbmRpbmcgb3JkZXIuIGBBbGV4YW5kZXJgIGZyb20gYExBYCBoYXMgdGhlIG1vc3QgdG90YWxfY291bnQgb2YgNDIgaG9zdGluZyBhbmQgcmFua3MgYXQgdGhlIGZpcnN0IHBsYWNlLiBPbiB0aGUgdG9wIDM1IGxpc3RpbmdzLCBvdmVyIHRoYW4gODUlIGFyZSBmcm9tIGBMQWAuIEl0IHNob3dzIHRoZSBjb25zaXN0YW50Y3kgYW5kIHByb2Zlc3Npb25pc20gZGlmZmVyZW5jZXMgYmV0d2VlbiBOWUMgYW5kIExBIGluIGdlbmVyYWwuIEluIHNob3J0LCBgTEFgIHRvcCBob3N0ZXJzIGFyZSBtb3JlIHJlbGlhYmxlIGFuZCBwcm9mZXNzaW9uYWwgdG8gbW9zdCByZW50ZXJzLgpgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiMgaG9zdF9pZCAKIyB3aGljaCBob3N0IGhhcyBtb3N0IHJlbnRhbCBsaXN0aW5nPyBUT1AgNjAgaG9zdCBJRCBpbiBlYWNoIGNpdHkKCmg0IDwtIGFpcmJuYl90b3RhbCAlPiUgCiAgc2VsZWN0KGhvc3RfaWQsaG9zdF9uYW1lLGNvdW50LGNpdHlfbmFtZSkgJT4lCiAgZ3JvdXBfYnkoaG9zdF9pZCxob3N0X25hbWUsY2l0eV9uYW1lKSAlPiUKICBzdW1tYXJpemUoVG90YWxfQ291bnQgPXN1bShjb3VudCxuYS5ybT1UUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKFRvdGFsX0NvdW50KSkgCgojIHNlbGVjdCB0b3AgMzAgaW4gTllDCmg0XzEgPC0gaDQgJT4lCiAgZmlsdGVyKGNpdHlfbmFtZSA9PSdOZXcgWW9yayBDaXR5JykgJT4lCiAgaGVhZCgzMCkKCiMgc2VsZWN0IHRvcCAzMCBpbiBMQQpoNF8yIDwtIGg0ICU+JQogIGZpbHRlcihjaXR5X25hbWUgPT0nTG9zIEFuZ2VsZXMnKSAlPiUKICBoZWFkKDMwKQoKaDRfMyA8LSByYmluZChoNF8xLGg0XzIpCmg0XzQgPC0gaDRfMyAlPiUKICBhcnJhbmdlKGRlc2MoVG90YWxfQ291bnQpKQogIApoZWFkKGg0XzQpCmBgYAoKIyMjI1RvcCA2MCBob3N0cyBpbiBOZXcgWW9yayBDaXR5IGFuZCBMb3MgQW5nZWxlcwpgYGB7ciBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTQsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQogZ2dwbG90KGg0XzQsIGFlcyh4PSByZW9yZGVyKGhvc3RfbmFtZSxUb3RhbF9Db3VudCkseT1Ub3RhbF9Db3VudCxjb2xvcj1jaXR5X25hbWUpKSArIAogIGdlb21fcG9pbnQoKSsKICB4bGFiKCJIb3N0IElEIikgKwogIGdndGl0bGUoIlRvcCBIb3N0cyBpbiBOZXcgWW9yayBDaXR5IFZzIExvcyBBbmdlbGVzIikgKwogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICBjb29yZF9mbGlwKCkKYGBgCgojIyMjVG9wIDUwIEhvc3RpbmcgaW4gTmV3IFlvcmsgQ2l0eQpgYGB7ciAgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpoNF8xXzEgPC0gaDQgJT4lCiAgZmlsdGVyKGNpdHlfbmFtZSA9PSdOZXcgWW9yayBDaXR5JykgJT4lCiAgaGVhZCg1MCkKaDRfMV8yIDwtc3Vic2V0KGg0XzFfMSwgc2VsZWN0PWMoImhvc3RfaWQiLCJob3N0X25hbWUiKSkKCmxpc3QwMzE3X255XzIgPC0gbGlzdDAzMTdfbnkKbGlzdDAzMTdfbnlfMiRwcmljZSA8LSBhcy5udW1lcmljKGdzdWIoIlxcJCIsICIiLCBsaXN0MDMxN19ueV8yJHByaWNlKSkgI3JlbW92ZSAkIHNpZ24Kc3ViX21lcmdlIDwtIHN1YnNldChsaXN0MDMxN19ueV8yLHNlbGVjdCA9YygiaG9zdF9pZCIsIm5laWdoYm91cmhvb2RfZ3JvdXBfY2xlYW5zZWQiLCJsYXRpdHVkZSIsCiAgICAgICAgICAgICAgICJsb25naXR1ZGUiLCJwcm9wZXJ0eV90eXBlIiwicm9vbV90eXBlIiwicHJpY2UiLCJtaW5pbXVtX25pZ2h0cyIsIm1heGltdW1fbmlnaHRzIikpCiMgTEVGVCBKT0lOCmgxX3RvdGFsIDwtIG1lcmdlKHggPSBoNF8xXzIsIHkgPSBzdWJfbWVyZ2UsIGJ5ID0gImhvc3RfaWQiLCBhbGwueCA9IFRSVUUpICMgdG9wIDUwIGhvc3QgSUQgTllDCgojIDUwIEhvc3QgTGlzdGluZyBpbiBOWUMKZzEgPC0gcW1wbG90KGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGRhdGEgPSBoMV90b3RhbCwgbWFwdHlwZSA9ICJ0b25lci1iYWNrZ3JvdW5kIiwKICAgICAgIGRhcmtlbiA9IDAuNiwgY29sb3IgPSByb29tX3R5cGUsYWxwaGEgPUkoMC40KSxzaXplID0gSSgwLjYpKSsKICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MykpKSArCiAgICAgIGdndGl0bGUoIlRvcCA1MCBIb3N0IGluIE5ldyBZb3JrIikgKwogICAgICB0aGVtZShsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkKZzIgPC0gcW1wbG90KGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGRhdGEgPSBoMV90b3RhbCwgbWFwdHlwZSA9ICJ0b25lci1iYWNrZ3JvdW5kIiwKICAgICAgIGRhcmtlbiA9IDAuNiwgY29sb3IgPSBwcm9wZXJ0eV90eXBlLGFscGhhID1JKDAuNCksc2l6ZSA9IEkoMC42KSkgKwogICAgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0zKSkpICsKICAgICAgZ2d0aXRsZSgiVG9wIDUwIEhvc3QgaW4gTmV3IFlvcmsiKSsKICAgICAgdGhlbWUobGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpCmdyaWQuYXJyYW5nZShnMSxnMiwgbnJvdz0xKQpgYGAKCiMjIyNUb3AgNTAgSG9zdGluZyBpbiBMb3MgQW5nZWxlcwoKYGBge3Igd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQojVG9wIDUwIEhvc3QgSUQgTEEKIyMjIyMjIyMjIyMjIyMjIyMjIwpoNF8xXzFfbGEgPC0gaDQgJT4lCiAgZmlsdGVyKGNpdHlfbmFtZSA9PSdMb3MgQW5nZWxlcycpICU+JQogIGhlYWQoNTApCmg0XzFfMl9sYSA8LXN1YnNldChoNF8xXzFfbGEsIHNlbGVjdD1jKCJob3N0X2lkIiwiaG9zdF9uYW1lIikpCgpsaXN0MDMxN19sYV8yIDwtIGxpc3QwMzE3X2xhCmxpc3QwMzE3X2xhXzIkcHJpY2UgPC0gYXMubnVtZXJpYyhnc3ViKCJcXCQiLCAiIiwgbGlzdDAzMTdfbGFfMiRwcmljZSkpICNyZW1vdmUgJCBzaWduCnN1Yl9tZXJnZV9sYSA8LSBzdWJzZXQobGlzdDAzMTdfbGFfMixzZWxlY3QgPWMoImhvc3RfaWQiLCJuZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkIiwibGF0aXR1ZGUiLAogICAgICAgICAgICAgICAibG9uZ2l0dWRlIiwicHJvcGVydHlfdHlwZSIsInJvb21fdHlwZSIsInByaWNlIiwibWluaW11bV9uaWdodHMiLCJtYXhpbXVtX25pZ2h0cyIpKQojIExFRlQgSk9JTgpoMV90b3RhbF9sYSA8LSBtZXJnZSh4ID0gaDRfMV8yX2xhLCB5ID0gc3ViX21lcmdlX2xhLCBieSA9ICJob3N0X2lkIiwgYWxsLnggPSBUUlVFKSAjIHRvcCA1MCBob3N0IElEIExBCgpnMyA8LSBxbXBsb3QobG9uZ2l0dWRlLCBsYXRpdHVkZSwgZGF0YSA9IGgxX3RvdGFsX2xhLCBtYXB0eXBlID0gInRvbmVyLWJhY2tncm91bmQiLAogICAgICAgZGFya2VuID0gMC42LCBjb2xvciA9IHJvb21fdHlwZSxhbHBoYSA9SSgwLjQpLHNpemUgPSBJKDAuNikpKwogICAgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0zKSkpICsKICAgICAgZ2d0aXRsZSgiVG9wIDUwIEhvc3QgaW4gTG9zIEFuZ2VsZXMiKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKQpnNCA8LSBxbXBsb3QobG9uZ2l0dWRlLCBsYXRpdHVkZSwgZGF0YSA9IGgxX3RvdGFsX2xhLCBtYXB0eXBlID0gInRvbmVyLWJhY2tncm91bmQiLAogICAgICAgZGFya2VuID0gMC42LCBjb2xvciA9IHByb3BlcnR5X3R5cGUsYWxwaGEgPUkoMC40KSxzaXplID0gSSgwLjYpKSArCiAgICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTMpKSkgKwogICAgICBnZ3RpdGxlKCJUb3AgNTAgSG9zdCBpbiBMb3MgQW5nZWxlcyIpKwogICAgICB0aGVtZShsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkKZ3JpZC5hcnJhbmdlKGczLGc0LCBucm93PTEpCmBgYApGcm9tIHRoZSB0b3AgNTAgSG9zdCBMaXN0aW5nIHBsb3QgaW4gTllDLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1vc3Qgcm9vbSB0eXBlIGlzIGBQcml2YXRlIHJvb21gIGFuZCB0aGUgbW9zdCBwcm9wZXJ0eV90eXBlIGlzIGBBcGFydG1lbnRgOyB3aGVyZWFzIGluIExBLCB0aGUgbW9zdCByb29tIHR5cGVzIGFyZSBgRW50aXJlIGhvbWUvYXB0YCBhbmQgYFNoYXJlZCByb29tYCwgYW5kIGBIb3VzZWAgYW5kIGBMb2Z0YCBhcmUgdGhlIHR3byBtYWluIHByb3BlcnR5X3R5cGVzIHRoYXQgYXJlIG1vc3RseSBkZXRlcm1pbmVkIGJ5IHRoZSBhcmVhcy4gSW4gYWRkaXRpb24sIGlmIGl0J3MgbG9jYXRlZCBtb3JlIGNsb3NlIHRvIGBkb3dudG93bmAgYW5kIGBVQ0xBYCBhcmVhLCB3ZSBjYW4gYWxzbyBzZWUgc29tZSBgQXBhcnRtZW50YCBhbmQgYENvbmRvbWluaXVtYCBwb2ludCBwbG90cyBzaG93aW5nIHVwLiAKCiMjIyNGYWNldHRpbmcgTU9TQUlDIGZvciBzdXBlcmhvc3QvdmVyaWZpZWQgaG9zdC9uZWlnaGJvcmhvb2QgaW4gTllDCgpgYGB7ciwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQojRmFjZXR0aW5nIE1PU0FJQyBmb3Igc3VwZXJob3N0LCB2ZXJpZmllZCwgbmVpZ2hicHJob29kIGluIE5ZQwoKbXNjIDwtIHN1YnNldChsaXN0MDMxN19ueSxzZWxlY3QgPSBjKGhvc3RfaWRlbnRpdHlfdmVyaWZpZWQsIG5laWdoYm91cmhvb2RfZ3JvdXBfY2xlYW5zZWQsaG9zdF9pc19zdXBlcmhvc3QgKSApCm1zYyA8LSBtc2NbbXNjJGhvc3RfaWRlbnRpdHlfdmVyaWZpZWQhPSIiLF0KbGV2ZWxzKG1zYyRob3N0X2lkZW50aXR5X3ZlcmlmaWVkKSA8LSBjKGxldmVscyhtc2MkaG9zdF9pZGVudGl0eV92ZXJpZmllZCksICJZRVMiLCJOTyIpCmxldmVscyhtc2MkaG9zdF9pc19zdXBlcmhvc3QpIDwtIGMobGV2ZWxzKG1zYyRob3N0X2lzX3N1cGVyaG9zdCksICJTdXBlcmhvc3QiLCJOb3QgU3VwZXJob3N0IikKCm1zYyRob3N0X2lkZW50aXR5X3ZlcmlmaWVkW21zYyRob3N0X2lkZW50aXR5X3ZlcmlmaWVkID09ICJ0Il0gPC0gIllFUyIKbXNjJGhvc3RfaWRlbnRpdHlfdmVyaWZpZWRbbXNjJGhvc3RfaWRlbnRpdHlfdmVyaWZpZWQgPT0gImYiXSA8LSAiTk8iCm1zYyRob3N0X2lzX3N1cGVyaG9zdFttc2MkaG9zdF9pc19zdXBlcmhvc3QgPT0gInQiXSA8LSAiU3VwZXJob3N0Igptc2MkaG9zdF9pc19zdXBlcmhvc3RbbXNjJGhvc3RfaXNfc3VwZXJob3N0ID09ICJmIl0gPC0gIk5vdCBTdXBlcmhvc3QiCgptb3NhaWMgPC0gZ2dwbG90KGRhdGEgPSBtc2MpICsKICAgZ2VvbV9tb3NhaWMoIGFlcyggeCA9IHByb2R1Y3QoaG9zdF9pZGVudGl0eV92ZXJpZmllZCwgbmVpZ2hib3VyaG9vZF9ncm91cF9jbGVhbnNlZCksIGZpbGw9ZmFjdG9yKGhvc3RfaWRlbnRpdHlfdmVyaWZpZWQpKSwgIG5hLnJtPVRSVUUpICsgICAgIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGxhYnMoeD0iTmVpZ2hib3Job29kcyIsIHRpdGxlPSdOWUMgdmVyaWZpZWQgaG9zdHMsIHN1cGVyaG9zdHMgTmVpZ2hib3Job29kcyAnKSAgKwogIGZhY2V0X2dyaWQoaG9zdF9pc19zdXBlcmhvc3R+LikgKyAKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGUgPSAiSWRlbnRpdHkgVmVyaWZpZWQiKSApIAoKYGBgCiFbXSgvVXNlcnMvS2V2aW5zbmFwc2hvdy9Db2x1bWJpYSBVbml2ZXJzaXR5IEVtYWlsL0VEVi9SX2NvZGUvZmlnbW9zYWljLnBuZykKClRoaXMgaXMgYSBmYWNldHRpbmcgbW9zYWljIHBsb3QgY29tcGFyaW5nIHRoZSBudW1iZXIgb2YgaG9zdHMvdmVyaWZpZWQgaG9zdHMvc3VwZXJob3N0cyBpbiBkaWZmZXJlbnQgbmVpZ2hib3Job29kcyBpbiBuZXcgeW9yayBjaXR5LiAgCgpGaXJzdGx5LCB3ZSBjYW4gbG9vayBhdCBob3cgaG9zdHMgaXMgZGlzdHJpYnV0ZWQgaW4gZGlmZmVybmV0IG5laWdoYm9yaG9vZHMuIEl0IGlzIGVhc2lseSB0byBzZWUgdGhhdCBNYW5oYXR0YW4gYW5kIEJyb29rbHluIGhhdmUgbXVjaCBsYXJnZXIgYW1vdW50IG9mIGhvc3RzIHRoYW4gb3RoZXIgbmVpZ2hib3Job29kcy4gU3RhdGVuIElzbGFuZCBpcyBubyBkb3VidCBvY2N1cHlpbmcgdGhlIHNtYWxsZXN0IHBhcnQuICAgTmV4dCwgd2Ugd2lsbCBsb29rIGF0IHRoZSB2ZXJpZmllZCBob3N0cyBhbmQgdW52ZXJpZmllZCBob3N0cy4gU3VycHJpc2luZ2x5LCB1bnZlcmlmaWVkIGhvc3RzIHNlZW0gdG8gaGF2ZSBhIGxhcmdlciBwZXJjZW50YWdlIGluIE1hbmhhdHRhbiB0aGFuIGluIEJyb29rbHluLiBBbmQgaXQgaXMgYWxzbyBub3RpZWFibGUgdGhhdCB1bnZlcmlmaWVkIGhvc3RzIGFyZSBjb3VudGluZyBhIHJhdGhlciBsYXJnZSBwZXJjZW50YWdlIGluIHRoZSB0b3RhbCBudW1iZXIgb2YgaG9zdHMuIFVzdWFsbHkgdGhlIHRyYXZlbGxlcnMgd2lsbCBsaWtlIHRvIGxpdmUgaW4gYSBtb3JlIHNlY3VyZSBzcGFjZSBzbyB2ZXJpZmljYXRpb24gaXMgYW4gaW1wb3J0YW50IGZhY3RvciB3aGVuIG9uZSBpcyBsb29raW5nIGZvciBhY2NvbW1vZGF0aW9ucy4gU3VjaCBhIGxhcmdlIHBlcmNlbnRhZ2Ugb2YgdW52ZXJpZmllZCBob3N0cyBnaXZlIHVzIHR3byBndWVzc2VzLiBPbmUgaXMgdGhhdCBwZW9sZSBoZXJlIGFyZSBzbyBjb25jZXJuZWQgYWJvdXQgdGhlaXIgcHJpdmFjeSB0aGF0IHRoZXkgZG8gbm90IHdhbnQgdG8gYmUgdmVyaWZpZWQgZXZlbiBqdXN0IGJ5IEFpcmJuYi4gVGhlIG90aGVyIG9uZSBpcyB0aGF0IGFjY29tbW9kYXRpb25zIGluIG5ldyB5b3JrIGNpdHkgaXMgc28gcHJpY3kgdGhhdCB0cmF2ZWxsZXIgd2lsbCBtb3JlIHRoYW4gd2lsbGluZ2x5IHRvIHBheSBhIGxvd2VyIHByaWNlIGFuZCBsZWF2ZSB0aGUgdmVyaWZpY2F0aW9uIGlzc3VlIGFsb25lLiAgCgpMYXN0bHksIHRoZSBzdXBlcmhvc3RzLiBXaGVuIHdlIGZhY2V0IHdpdGggc3VwZXJob3N0LCBpdCBpcyBub3QgYWNjb3JkaW5nIHRvIHRoZSBwZXJjZW50YWdlIG9mIHN1cGVyaG9zdCBvciBub3QuIEluIGZhY3QsIHRoZSBudW1iZXIgb2Ygc3VwZXJob3N0cyBpcyBtdWNoIHNtYWxsZXIgdGhhbiB0aGUgb25lIG9mIG5vdCBzdXBlcmhvc3RzLiBCdXQgaXQgaXMgdmVyeSByZWFzb25hYmxlIHNpbmNlIG9ubHkgdGhlIHRvcCBob3N0cyBjYW4gYmUgZGVlbWVkIGFzIHN1cGVyaG9zdHMgYnkgQWlyYm5iLiBGb3IgZXhhbXBsZSwgd2hlbiB5b3Ugd2FudCB0byBidXkgc29tZXRoaW5nIG9uIGVCYXksIHlvdSB3aWxsIHdhbnQgdG8gbG9vayBhdCB0b3AgcmF0ZWQgc2VsbGVycy4gSWYgZXZlcnlvbmUgaXMgdG9wIHJhdGVkIHNlbGxlciwgdGhlbiB0aGUgdGl0bGUgaXMgbWVhbmluZ2xlc3MuIE9uZSBjYW4gZWFzaWx5IG5vdGljZSB0aGF0IHZlcmlmaWVkIHN1cGVyaG9zdHMgYXJlIGNvdmVyaW5nIGEgbGFyZ2VyIGFyZWEgY29tcGFyZWQgdG8gbm90IHN1cGVyaG9zdHMgZmFjZXQuIEFuZCBvbmUgdmVyeSBpbXBvcnRhbnQgZmluZGluZyBpcyB0aGF0LCBCcm9va2x5biBzZWVtcyB0byBoYXZlIG1vcmUgc3VwZXJob3N0cyB0aGFuIE1hbmhhdHRhbiwgd2hpY2ggaXMgZ2VudWlubHkgdW5leHBlY3RlZC4gTWF5YmUgaXQgaXMgYSBwcm9vZiBvZiBzdWNjZXNzIGluIGdlbnRyaWZpY2F0aW9uLgoKIyMjIFJldmlldyBTY29yZSBSYXRpbmcgQW5hbHlzaXMgCkFub3RoZXIgaW1wb3J0YW50IG1ldHJpYyBmb3Igb3VyIGRhdGEgYW5hbHlzaXMgaXMgdGhlIGBSZXZpZXcgU2NvcmUgUmF0aW5nYC4gV2Ugd2FudCB0byBleHBsb3JlIGFuZCBzZWUgaWYgdGhlcmUncyBhbnkgbWFqb3IgZmFjdG9yIHRoYXQgd2lsbCBtYWtlIGRpZmZlcmVuY2Ugb24gdGhlIFJldmlldyBTY29yZSBSYXJ0aW5nIG9mIHRoZSBob3N0IGxpc3RpbmdzLiBXZSBzZWxlY3RlZCBgTnVtYmVyIG9mIFJldmlld3NgLCBgaG9zdF9pc19zdXBlcmhvc3RgIGFuZCBgaG9zdF9yZXNwb25zZV90aW1lYCBhcyBhbm90aGVyIHRocmVlIHZhcmlhYmxlcyB0byB2aXN1bGFpemUgdGhlIHJlbGF0aW9uc2hpcCBhc3NvY2lhdGVkIHdpdGggYFJldmlldyBTY29yZSBSYXRpbmdgLgoKIyMjIyBSUmV2aWV3IFNjb3JlIFJhdGluZyB2cyBTdXBlcmhvc3QKYGBge3IgIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0Kc3VtbWFyeShhaXJibmJfdG90YWwkaG9zdF9pc19zdXBlcmhvc3QpCnJlX3N1cGVyIDwtIHN1YnNldChhaXJibmJfdG90YWwsaG9zdF9pc19zdXBlcmhvc3QgIT0iIikgI3JlbW92ZSBtaXNzaW5nIHZhbHVlCmdncGxvdChyZV9zdXBlciwgYWVzKG51bWJlcl9vZl9yZXZpZXdzLCByZXZpZXdfc2NvcmVzX3JhdGluZykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBmYWN0b3IoaG9zdF9pc19zdXBlcmhvc3QpKSxhbHBoYSA9MC42KSArCiAgeGxhYigiTnVtYmVyIG9mIFJldmlld3MiKSArCiAgeWxhYigiUmV2aWV3IFNjb3JlcyBSYXRpbmciKSArCiAgZ2d0aXRsZSgiIERpc3RyaWJ1dGlvbiBvZiBSZXZpZXcgU2NvcmVzIFJhdGluZyBieSBTdXBlciBIb3N0ICIpICsKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjcpKSArCiAgZmFjZXRfd3JhcCggfiBob3N0X2lzX3N1cGVyaG9zdCkKYGBgCkFzIHdlIGNhbiBzZWUgZnJvbSB0aGUgYWJvdmUgc2NhdHRlciBwbG90LCAgdGhlIG1vcmUgbnVtYmVyIG9mIHJldmlld3MgdGhlIGhvc3QgY2FuIGhhdmUsIHRoZSBtb3JlIGNoYW5jZXMgdGhhdCB0aGUgaG9zdCB3aWxsIGdldCBoaWdoZXIgUmV2aWV3IHNjb3JlIHJhdGluZy4gSW4gdGhlIG1lYW4gdGltZSwgaWYgdGhlIGhvc3QgaXMgYSBzdXBlciBob3N0LCB0aGUgcmV2aWV3IHNjb3JlIHJhdGluZyB3aWxsIGJlIGF0IGxlYXN0IDgwLgoKIyMjIyBSZXZpZXcgU2NvcmUgUmF0aW5nIHZzIEhvc3QgUmVzcG9uc2UgVGltZQpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CnN1bW1hcnkoYWlyYm5iX3RvdGFsJGhvc3RfcmVzcG9uc2VfdGltZSkKc3VtbWFyeShhaXJibmJfdG90YWwkcmV2aWV3X3Njb3Jlc19yYXRpbmcpCnMgPC0gc3Vic2V0KGFpcmJuYl90b3RhbCwgaG9zdF9yZXNwb25zZV90aW1lICE9ICdOL0EnICYgaG9zdF9yZXNwb25zZV90aW1lICE9IiIpCiAgCmdncGxvdChzLCBhZXMocmV2aWV3X3Njb3Jlc19yYXRpbmcsY29sb3VyID0gaG9zdF9yZXNwb25zZV90aW1lKSkgKwogIGdlb21fZGVuc2l0eShzaXplPTEsIHNob3dfZ3VpZGU9RkFMU0UpICsKICB4bGFiKCJSZXZpZXcgU2NvcmVzIFJhdGluZyIpICsKICB4bGltKDU1LCAxMDApICsKICBnZ3RpdGxlKCJEaXN0cmlidXRpb24gb2YgUmV2aWV3IFNjb3JlcyBSYXRpbmcgYnkgUmVzcG9uc2UgVGltZSIpICsKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArIAogIHN0YXRfZGVuc2l0eShhZXMoeD1yZXZpZXdfc2NvcmVzX3JhdGluZywgY29sb3VyPWhvc3RfcmVzcG9uc2VfdGltZSksIGdlb209ImxpbmUiLCBwb3NpdGlvbj0iaWRlbnRpdHkiICkgICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0yKSkpCmBgYApBcyB3ZSBjYW4gc2VlIGZyb20gdGhlIG11bHRpcGxlIGRlc25zaXR5IGN1cnZlcywgdGhlcmUgYXJlIHF1aXRlIGEgZmV3IHBlb3BsZSBnaXZpbmcgc2NvcmVzIGFyb3VuZCA2MCBhbmQgNzAuIFZlcnkgZmV3IHBlb3BsZSBhcmUgZ2l2aW5nIHNjb3JlcyB1bmRlciA2MCBzbyB3ZSBlbGltaW5hdGUgdGhlIHBhcnQgdW5kZXIgNTAuIEEgbGFyZ2VyIHBlcmNlbnRhZ2Ugb2YgcGVvcGxlIHN0YXJ0cyB0byBnaXZlIHNjb3JlcyBhdCA4MC4gVGhlbiBpdCBkcm9wcyBhZ2Fpbi4gSG93ZXZlciwgdGhlcmXigJlzIGEgYmlnIGRpZmZlcmVuY2UgaW4gcGVyY2VudGFnZXMgd2hlbiBwZW9wbGUgZ2l2ZSBzY29yZXMgaGlnaGVyIHRoYW4gOTAgYXQgdGhlIGVuZCBvZiB0aGUgcGxvdC4gV2UgY2FuIHNlZSB0aGF0ICJhIGZldyBkYXlzIGFuZCBtb3JlIiBhcmUgY2xlYXJseSBsb3dlciB0aGFuIHRoZSBvdGhlciBkZW5zaXR5IGN1cnZlcy4gSXQgbWF5IHdlbGwgaW5kaWNhdGUgdGhhdCBwZW9wbGUgY2FuIGNlcnRhaW5seSB0b2xlcmFudCBhIHJlc3BvbnNlIHdpdGhpbiBhIGRheS4gVGhleSBtYXkgYmUgaW5kaWZmZXJlbnQgd2l0aCBvbmUgaG91ciBvciBhIGRheS4gQnV0LCBpZiBpdOKAmXMgYmV5b25kIGEgZGF5IHRvIHJlcHNvbmQsIHRoZSBtb3JlIHByb2JhYmx5IHRoYXQgdGhlIGhvc3Qgd2lsbCBub3QgaGF2ZSBoaWdoZXIgc2NvcmUgcmF0aW5nIGV2ZW50dWFsbHkuCgojIyBDb25jbHVzaW9uClRoZXJlIGFyZSBzZXZlcmFsIGxpbWl0YXRpb25zIGluIG91ciBjdXJyZW50IHByb2Nlc3MuIEZpcnN0bHksIHRoZSBvcmlnaW5hbCBkYXRhc2V0cyBhcmUgbm90IHBlcmZlY3QuIENlcnRhaW4gZmVhdHVyZXMgYXJlIG5vdCBpbiBlYXJsaWVyIGRhdGFzZXRzLCB0aHVzIHRoZXkgYXJlIG5vdCBjb25zaXN0ZW50IGluIHZhcmlhYmxlcy4gRGF0YXNldHMgYmVmb3JlIEphbiAyMDE1IGlzIHJhcmVseSBzZWVuIGluIHRoZSBkYXRhc2V0IGxpc3RzLiBTZWNvbmRseSwgbm8gZG9jdW1lbnRhdGlvbiBpcyBmb3VuZCBhbG9uZyB3aXRoIHRoZSBkYXRhc2V0LiBTbyB3ZSBoYXZlIHRvIG1ha2UgYW4gYXNzdW1wdGlvbiBvbiBzZXZlcmFsIGZlYXR1cmVzLCBzdWNoIGFzIGF2YWlsYWJpbGl0eV8zMCwgYXZhaWxhYmlsaXR5XzYwLCBhdmFpbGFiaWxpdHlfOTAsIGFuZCBhdmFpbGFiaWxpdHlfMzY1LiBUaGlyZGx5LCBzaW5jZSB3ZSBtaWdodCBsYWNrIGNvbnRpbnVvdXMgZGF0YSBvbiB0aGUgcHJpY2UgaW5mb3JtYXRpb24sIHdlIGNhbm5vdCBnZW5lcmF0ZSBmdXJ0aGVyIGV4cGxvcmF0b3J5IGFuYWx5c2lzIG9mIHByaWNlIG9uIGEgdGltZSBzZXJpZXMgc2NhbGUuIE5leHQsIHRoZSBkYXRhc2V0IGRvZXMgbm90IHByb3ZpZGUgYW55IGRhdGEgb24gdGhlIHNwYWNlIHNpemUgb2YgdGhlIGxpc3RpbmcgcmVudGFscy4gTW9zdCBvZiB0aGUgdmFsdWVzIGFyZSBtaXNzaW5nIG9yIGVxdWFsIHRvIHplcm8uIFdlIGNhbm5vdCBtYWtlIGEgZnVydGhlciBhbmFseXNpcyBvbiB0aGUgbGlzdGluZyBwcmljZSBjb21wYXJlZCB0byB0aGUgc2l6ZSBvZiB0aGUgc3BhY2UuIExhc3RseSwgaXQgZG9lcyBub3QgcHJvdmlkZSBuZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkIHZhcmlhYmxlIGluIExvcyBBbmdlbGVzLiBTbyBpdCBpcyBoYXJkIHRvIGlkZW50aWZ5IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHJvb20gdHlwZSwgcHJvcGVydHkgdHlwZSwgbWluaW11bSBuaWdodHMgb2Ygc3RheSBhbmQgcHJpY2UgLCBldGMsIHdpdGhpbiBMQSdzIGRpZmZlcmVudCBuZWlnaGJvcmhvb2RzLiBEaWZmZXJlbnQgYXJlYXMgbWF5IGhhdmUgZGlmZmVyZW50IHJlc3VsdCwgbGlrZSBOZXcgWW9yayBDaXR5LiBJZiB0aG9zZSBhcmVhcyBhcmUgaG90dGVzdCBzaWdodHNlZWluZyBvciByaWNoIGFyZWFzLCB0aGUgcHJpY2VzIG1heSByZWZsZWN0IHN1Y2ggZGlzdGluY3Rpb25zLgoKSW4gdGhlIGZ1dHVyZSBleHBsb3JhdGlvbiwgcHJvYmxlbXMgbWVudGlvbmVkIGFib3ZlIHNob3VsZCBiZSBmaXhlZCBhcyBtdWNoIGFzIHBvc3NpYmxlLiBGb3IgZXhhbXBsZSwgaXQgbWlnaHQgYmUgYSBncmVhdCBpZGVhIHRvIGRvIG1vcmUgY2xlYW5pbmcgd29yayBvbiB0aGUgb3JpZ2luYWwgZGF0YXNldC4gV2UgY2FuIGNsZWFuIHRoZSBtZXNzeSB2YWx1ZXMgaW4gbmVpZ2hib3Job29kIHZhcmlhYmxlIGluIExvcyBBbmdlbGVzIGRhdGFzZXQgd2l0aCBmdXJ0aGVyIGtub3dsZWRnZSBpbiBMb3MgQW5nZWxlcyBnZW9ncmFwaGljIGluZm9ybWF0aW9uLiBXaXRoIHN1Y2ggY2xlYW4gdmFsdWVzLCB3ZSBjb3VsZCBmdXJ0aGVyIGtub3cgaG93IHRoZSBwcmljZS9yZXZpZXcgcmF0aW5ncy9hdmFpbGFiaWxpdGllcyBkaXN0cmlidXRlcyBpbiBjb29yZGluYXRpb24gd2l0aCBvdGhlciB2YXJpYWJsZXMuIFRoZXkgbWF5IGJlIGFmZmVjdGVkIGJ5IGRpZmZlcmVudCBwb3RlbnRpYWwgZmFjdG9ycyB3aXRoaW4gdGhlIHpvbmUuIEZvciBhbm90aGVyIHRoaW5nLCB3ZSBjYW4gc3dpdGNoIG91ciBnZWFyIHRvIGNoZWNrIG9uIHRoZSBjb25zdHJ1Y3Rpb24gb2Ygc2NvcmUgcmF0aW5nIHRvIGtub3cgd2hhdCB0cmF2ZWxsZXJzIGNhcmUgbW9zdCB3aGVuIHRoZXkgZ2l2ZSBhIHJhdGluZyBvbiBBaXJibmIuIFRoZXJlIGFyZSBtYW55IGFzcGVjdHMgY2FuIGJlIGltcHJvdmVkIGluIHRoZSBmdXR1cmUuCgpJbiB0aGlzIHByb2plY3QsIHdlIGdldCBhIHRvdWNoIG9mIHRoZSByZWFsIHdvcmxkIGRhdGEgYW5kIGhhdmUgbGVhcm5lZCBtdWNoIGR1cmluZyB0aGUgcHJvY2Vzcy4gQ2xlYW5pbmcgZGF0YSBpcyBubyBkb3VidCBvbmUgdmVyeSBpbXBvcnRhbnQgcGFydCB3aGVuIHlvdSBnZXQgaGFuZHMgZG93biBvbnRvIHJhdyBkYXRhLkFuZCB0byB1bmRlcnN0YW5kIHRoZSBtZWFuaW5nIG9mIGVhY2ggdmFyaWFibGUsIHRvIGltYWdpbmUgdGhlIGNvcnJlbGF0aW9uc2hpcCBiZXR3ZWVuICB2YXJpYWJsZXMsIGFuZCB0byB2YWxpZGF0ZSBvdXIgYXNzdW1wdGlvbnMgdXNpbmcgYSBzdWl0YWJsZSB0eXBlIG9mIHZpc3VhbGl6YXRpb24gYXJlIGFsbCBwcmVjaW91cyBleHBlcmllbmNlcyBpbiB0aGlzIHByb2plY3QuIFdlIHRyaWVkIGRpZmZlcmVudCB0eXBlcyBvZiBwbG90cyB1c2luZyB0aGUgc2FtZSB2YXJpYWJsZXMgdG8gZ2V0IHRoZSBiZXN0IHJlc3VsdHMuIFRoYXQgaXMgd2hhdCB2aXN1YWxpemF0aW9uIG5lZWRzIGluIHJlYWwgZGF0YSBleHBsb3JhdGlvbi4KCiMjIyNSZXByb2R1Y2liaWxpdHkKRG93bmxvYWQgdGhlIGRhdGFzZXRzIGFuZCB3aXRoIHRyaXZpYWwgZmlsZSByZW5hbWluZywgdGhlIGNvZGUgc2hvdWxkIGJlIHJ1biB3aXRob3V0IGVycm9yLiAod2l0aCBwYWNrYWdlIGluc3RhbGxlZCkgT25lIHRoaW5nIHRvIG5vdGljZSB0aGF0LCBtb3NhaWMgcGxvdCBpcyBhbiBpbnNlcnRlZCBpbWFnZS4gSWYgeW91IGNoYW5nZSB0aGUgY29kZSB0byBzaG93IHRoZSBtb3NhaWMgcGxvdC4gSXQgd2lsbCBzaG93IHRoZSBleGFjdGx5IHNhbWUgcGxvdCBqdXN0IHdpdGhvdXQgdGhlIHggYXhpcyBsYWJlbHMuIEl0IGlzIGEgbWlub3IgZGlzZnVuY3Rpb24gd2l0aCBnZ21vc2FpYy4gV2UgY2hhbmdlIHRoZSBsYWJlbHMgdW5kZXIgdGhlIGluc3RydWN0b3JzJ3MgaW5zdHJ1Y3Rpb24uCgpBbGwgc291cmNlcyBhcmUgY2l0ZWQgd2l0aCBsaW5rcy4=